@ascenda-one/github-collector 0.1.15 → 0.1.17
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/cli.js +1755 -187
- package/dist/mapForgeEvent.js +10 -16
- package/dist/mapForgeEvent.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -200,6 +200,102 @@ var require_workMilestoneClassifier = __commonJS({
|
|
|
200
200
|
}
|
|
201
201
|
});
|
|
202
202
|
|
|
203
|
+
// ../packages/tool-kit/out/autonomyBand.js
|
|
204
|
+
var require_autonomyBand = __commonJS({
|
|
205
|
+
"../packages/tool-kit/out/autonomyBand.js"(exports) {
|
|
206
|
+
"use strict";
|
|
207
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
208
|
+
exports.autonomyBand = autonomyBand;
|
|
209
|
+
function autonomyBand(mode) {
|
|
210
|
+
if (typeof mode !== "string")
|
|
211
|
+
return "unknown";
|
|
212
|
+
return BAND_BY_MODE[mode] ?? "unknown";
|
|
213
|
+
}
|
|
214
|
+
var BAND_BY_MODE = {
|
|
215
|
+
plan: "planning",
|
|
216
|
+
default: "supervised",
|
|
217
|
+
accept_edits: "edits_auto",
|
|
218
|
+
// Two tokens, one band — and the reason the tokens stayed two. They differ
|
|
219
|
+
// in how the user arrived at the posture rather than in how much the agent
|
|
220
|
+
// may then do unasked, so today they read the same. If that ever stops being
|
|
221
|
+
// true, this line changes and the whole corpus re-reads correctly, because
|
|
222
|
+
// the wire never collapsed them.
|
|
223
|
+
auto: "delegated",
|
|
224
|
+
dont_ask: "delegated",
|
|
225
|
+
bypass_permissions: "unsupervised"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// ../packages/tool-kit/out/modelClassifier.js
|
|
231
|
+
var require_modelClassifier = __commonJS({
|
|
232
|
+
"../packages/tool-kit/out/modelClassifier.js"(exports) {
|
|
233
|
+
"use strict";
|
|
234
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
235
|
+
exports.classifyModelClass = classifyModelClass;
|
|
236
|
+
function classifyModelClass(raw) {
|
|
237
|
+
const candidate = raw;
|
|
238
|
+
if (candidate === void 0 || candidate === null)
|
|
239
|
+
return void 0;
|
|
240
|
+
if (typeof candidate !== "string")
|
|
241
|
+
return "unknown";
|
|
242
|
+
const value = candidate.trim().toLowerCase();
|
|
243
|
+
if (!value)
|
|
244
|
+
return void 0;
|
|
245
|
+
if (ROUTER_SENTINEL.test(value))
|
|
246
|
+
return "router:auto";
|
|
247
|
+
const vendor = readModelVendor(value);
|
|
248
|
+
if (vendor === void 0)
|
|
249
|
+
return "unknown";
|
|
250
|
+
for (const [pattern, modelClass] of TIER_PATTERNS_BY_VENDOR[vendor]) {
|
|
251
|
+
if (pattern.test(value))
|
|
252
|
+
return modelClass;
|
|
253
|
+
}
|
|
254
|
+
return UNKNOWN_TIER_BY_VENDOR[vendor];
|
|
255
|
+
}
|
|
256
|
+
function readModelVendor(value) {
|
|
257
|
+
for (const [pattern, vendor] of VENDOR_PATTERNS) {
|
|
258
|
+
if (pattern.test(value))
|
|
259
|
+
return vendor;
|
|
260
|
+
}
|
|
261
|
+
return void 0;
|
|
262
|
+
}
|
|
263
|
+
var ROUTER_SENTINEL = /^(?:[a-z0-9][a-z0-9._-]*\/)?(?:auto|default)$/;
|
|
264
|
+
var VENDOR_PATTERNS = [
|
|
265
|
+
[/\b(anthropic|claude|opus|sonnet|haiku|fable)\b/, "anthropic"],
|
|
266
|
+
[/\b(openai|gpt|o[1-9])\b/, "openai"],
|
|
267
|
+
[/\b(google|gemini|vertex)\b/, "google"],
|
|
268
|
+
// xAI carries no corporate prefix in any observed id — the family name is
|
|
269
|
+
// the whole marker, exactly as `claude` and `gemini` are for theirs.
|
|
270
|
+
[/\b(xai|grok)\b/, "xai"],
|
|
271
|
+
[/\b(ollama|llamacpp|on[-_]?device|local)\b/, "local"]
|
|
272
|
+
];
|
|
273
|
+
var TIER_PATTERNS_BY_VENDOR = {
|
|
274
|
+
anthropic: [
|
|
275
|
+
[/\bopus\b/, "anthropic:opus"],
|
|
276
|
+
[/\bsonnet\b/, "anthropic:sonnet"],
|
|
277
|
+
[/\bhaiku\b/, "anthropic:haiku"],
|
|
278
|
+
[/\bfable\b/, "anthropic:fable"]
|
|
279
|
+
],
|
|
280
|
+
openai: [[/\bgpt\b/, "openai:gpt"]],
|
|
281
|
+
google: [[/\bgemini\b/, "google:gemini"]],
|
|
282
|
+
// One tier for now. The line's coding variants (`grok-code-fast-1`) are the
|
|
283
|
+
// same tier word plus a suffix, and splitting them off would be inventing a
|
|
284
|
+
// distinction the ids do not yet draw — `<vendor>:unknown` is waiting for
|
|
285
|
+
// the day one does.
|
|
286
|
+
xai: [[/\bgrok\b/, "xai:grok"]],
|
|
287
|
+
local: [[/\b(ollama|llamacpp|on[-_]?device)\b/, "local:on_device"]]
|
|
288
|
+
};
|
|
289
|
+
var UNKNOWN_TIER_BY_VENDOR = {
|
|
290
|
+
anthropic: "anthropic:unknown",
|
|
291
|
+
openai: "openai:unknown",
|
|
292
|
+
google: "google:unknown",
|
|
293
|
+
xai: "xai:unknown",
|
|
294
|
+
local: "local:unknown"
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
203
299
|
// ../packages/tool-kit/out/buckets.js
|
|
204
300
|
var require_buckets = __commonJS({
|
|
205
301
|
"../packages/tool-kit/out/buckets.js"(exports) {
|
|
@@ -294,89 +390,6 @@ var require_afterHours = __commonJS({
|
|
|
294
390
|
}
|
|
295
391
|
});
|
|
296
392
|
|
|
297
|
-
// ../packages/tool-kit/out/payload.js
|
|
298
|
-
var require_payload = __commonJS({
|
|
299
|
-
"../packages/tool-kit/out/payload.js"(exports) {
|
|
300
|
-
"use strict";
|
|
301
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
302
|
-
exports.getString = getString;
|
|
303
|
-
exports.getNumber = getNumber;
|
|
304
|
-
exports.getNested = getNested;
|
|
305
|
-
exports.getNestedString = getNestedString;
|
|
306
|
-
exports.getNestedNumber = getNestedNumber;
|
|
307
|
-
exports.inferOutcome = inferOutcome;
|
|
308
|
-
exports.outcomeForHook = outcomeForHook;
|
|
309
|
-
exports.looksLikeCorrection = looksLikeCorrection;
|
|
310
|
-
function getString(input, keys) {
|
|
311
|
-
for (const key of keys) {
|
|
312
|
-
const value = input[key];
|
|
313
|
-
if (typeof value === "string" && value.trim())
|
|
314
|
-
return value;
|
|
315
|
-
}
|
|
316
|
-
return void 0;
|
|
317
|
-
}
|
|
318
|
-
function getNumber(input, keys) {
|
|
319
|
-
for (const key of keys) {
|
|
320
|
-
const value = input[key];
|
|
321
|
-
if (typeof value === "number" && Number.isFinite(value))
|
|
322
|
-
return value;
|
|
323
|
-
}
|
|
324
|
-
return void 0;
|
|
325
|
-
}
|
|
326
|
-
function getNested(input, path) {
|
|
327
|
-
let current = input;
|
|
328
|
-
for (const segment of path) {
|
|
329
|
-
if (!current || typeof current !== "object")
|
|
330
|
-
return void 0;
|
|
331
|
-
current = current[segment];
|
|
332
|
-
}
|
|
333
|
-
return current;
|
|
334
|
-
}
|
|
335
|
-
function getNestedString(input, paths) {
|
|
336
|
-
for (const path of paths) {
|
|
337
|
-
const value = getNested(input, path);
|
|
338
|
-
if (typeof value === "string" && value.trim())
|
|
339
|
-
return value;
|
|
340
|
-
}
|
|
341
|
-
return void 0;
|
|
342
|
-
}
|
|
343
|
-
function getNestedNumber(input, paths) {
|
|
344
|
-
for (const path of paths) {
|
|
345
|
-
const value = getNested(input, path);
|
|
346
|
-
if (typeof value === "number" && Number.isFinite(value))
|
|
347
|
-
return value;
|
|
348
|
-
}
|
|
349
|
-
return void 0;
|
|
350
|
-
}
|
|
351
|
-
function inferOutcome(input) {
|
|
352
|
-
const exitCode = getNumber(input, ["exitCode", "exit_code", "status"]) ?? getNestedNumber(input, [["tool_response", "exitCode"], ["tool_response", "exit_code"], ["result", "exitCode"], ["result", "exit_code"]]);
|
|
353
|
-
if (typeof exitCode === "number")
|
|
354
|
-
return exitCode === 0 ? "success" : "failure";
|
|
355
|
-
const error = getString(input, ["error", "errorMessage"]) ?? getNestedString(input, [["tool_response", "error"], ["result", "error"]]);
|
|
356
|
-
if (error)
|
|
357
|
-
return "failure";
|
|
358
|
-
return "unknown";
|
|
359
|
-
}
|
|
360
|
-
function outcomeForHook(hookName, input) {
|
|
361
|
-
if (hookName === "PostToolUseFailure") {
|
|
362
|
-
const interrupted = input["is_interrupt"] === true || getNested(input, ["tool_response", "interrupted"]) === true;
|
|
363
|
-
return interrupted ? "cancelled" : "failure";
|
|
364
|
-
}
|
|
365
|
-
if (hookName === "PostToolUse") {
|
|
366
|
-
if (getNested(input, ["tool_response", "interrupted"]) === true)
|
|
367
|
-
return "cancelled";
|
|
368
|
-
return "success";
|
|
369
|
-
}
|
|
370
|
-
return "unknown";
|
|
371
|
-
}
|
|
372
|
-
function looksLikeCorrection(text) {
|
|
373
|
-
if (!text)
|
|
374
|
-
return false;
|
|
375
|
-
return /\b(wrong|incorrect|try again|fix|not what i asked|that's not|that is not|redo|regenerate|you missed|doesn't work|does not work)\b/i.test(text);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
|
|
380
393
|
// ../packages/tool-contract/out/metricKeys.js
|
|
381
394
|
var require_metricKeys = __commonJS({
|
|
382
395
|
"../packages/tool-contract/out/metricKeys.js"(exports) {
|
|
@@ -416,6 +429,42 @@ var require_metricKeys = __commonJS({
|
|
|
416
429
|
linesChangedBucket: { readBy: ["backend"], backendAliases: ["linesChangedBucket", "lines_changed_bucket"] },
|
|
417
430
|
// ── Read by the local handoff only ──────────────────────────────────────
|
|
418
431
|
activeMinutes: { readBy: ["handoff"], unit: "minutes" },
|
|
432
|
+
/**
|
|
433
|
+
* The two halves of `activeMinutes`, and deliberately two keys.
|
|
434
|
+
*
|
|
435
|
+
* They partition it exactly, so a reader can add them — but there is no
|
|
436
|
+
* third key holding the sum, because the sum is `activeMinutes` and it
|
|
437
|
+
* already exists. Presenting one combined "active" figure in place of these
|
|
438
|
+
* is the thing the split was added to stop: an hour of typing and an hour of
|
|
439
|
+
* watching an agent work are not the same hour, and a single number says
|
|
440
|
+
* they are.
|
|
441
|
+
*/
|
|
442
|
+
handsOnMinutes: {
|
|
443
|
+
readBy: ["handoff"],
|
|
444
|
+
unit: "minutes",
|
|
445
|
+
note: "Active time immediately preceding a human prompt \u2014 the only interval a transcript can show a person present for, because the prompt at its end is the evidence."
|
|
446
|
+
},
|
|
447
|
+
agentSupervisingMinutes: {
|
|
448
|
+
readBy: ["handoff"],
|
|
449
|
+
unit: "minutes",
|
|
450
|
+
note: "The remaining active time: the agent was working and the person was not typing. NOT a claim that anyone watched it \u2014 nothing in a transcript could show that. Never render as attention."
|
|
451
|
+
},
|
|
452
|
+
// The split's honesty counters. Read by neither the backend nor the handoff
|
|
453
|
+
// on purpose: they exist so a thin or posture-blind session can be told from
|
|
454
|
+
// a complete one, and a reader that ignores them is choosing to, rather than
|
|
455
|
+
// being unable to.
|
|
456
|
+
activeSplitInstants: {
|
|
457
|
+
readBy: ["diagnostic"],
|
|
458
|
+
note: "Distinct timestamps the split ran over, after collapsing ties. The denominator: two minutes off four instants and off four hundred are not the same measurement."
|
|
459
|
+
},
|
|
460
|
+
activeSplitUndatedLines: {
|
|
461
|
+
readBy: ["diagnostic"],
|
|
462
|
+
note: "Known lines carrying a timestamp that would not parse. Absent from the timeline, so both halves are short by an unknown amount and only this says so."
|
|
463
|
+
},
|
|
464
|
+
activeSplitUnposturedInstants: {
|
|
465
|
+
readBy: ["diagnostic"],
|
|
466
|
+
note: "Instants reached before any permissionMode had been declared. Their supervising time lands in the unknown band, which is a blind spot rather than a posture."
|
|
467
|
+
},
|
|
419
468
|
afterHoursRequests: { readBy: ["handoff"] },
|
|
420
469
|
approximateLintErrorsCount: { readBy: ["handoff"] },
|
|
421
470
|
canceledCount: { readBy: ["handoff"] },
|
|
@@ -429,6 +478,11 @@ var require_metricKeys = __commonJS({
|
|
|
429
478
|
unit: "tokens",
|
|
430
479
|
note: "The measured quantity, with no assumed denominator. Prefer this to the ratio for any within-person baseline."
|
|
431
480
|
},
|
|
481
|
+
contextWindowTokens: {
|
|
482
|
+
readBy: ["handoff"],
|
|
483
|
+
unit: "tokens",
|
|
484
|
+
note: "Codex only: the model_context_window the rollout itself recorded \u2014 the real denominator its contextWindowPeakPct was computed against. Claude Code records no window and its ratio assumes 200k; absent here means the store never said."
|
|
485
|
+
},
|
|
432
486
|
date: { readBy: ["handoff"] },
|
|
433
487
|
errorCount: { readBy: ["handoff"] },
|
|
434
488
|
filesChangedCount: { readBy: ["handoff"] },
|
|
@@ -512,6 +566,10 @@ var require_metricKeys = __commonJS({
|
|
|
512
566
|
unparsedLines: { readBy: ["diagnostic"] },
|
|
513
567
|
unreadableChatSessionFiles: { readBy: ["diagnostic"] },
|
|
514
568
|
unreadableHistoryFiles: { readBy: ["diagnostic"] },
|
|
569
|
+
unreadableRolloutFiles: {
|
|
570
|
+
readBy: ["diagnostic"],
|
|
571
|
+
note: "Codex only: rollout files the extractor meant to read and could not open. Summed into the import's read-failure warning, so a store that is partly unreadable says so rather than reporting a short window as the whole."
|
|
572
|
+
},
|
|
515
573
|
unrecognisedChatSessionFiles: { readBy: ["diagnostic"] }
|
|
516
574
|
};
|
|
517
575
|
function backendMetricKeys() {
|
|
@@ -525,7 +583,7 @@ var require_out = __commonJS({
|
|
|
525
583
|
"../packages/tool-contract/out/index.js"(exports) {
|
|
526
584
|
"use strict";
|
|
527
585
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
528
|
-
exports.backendMetricKeys = exports.METRIC_KEYS = exports.ASCENDA_SEMANTIC_PROVENANCE = exports.ASCENDA_HISTORICAL_CONSENT_SCOPE = exports.ASCENDA_COLLABORATION_CONSENT_SCOPE = exports.ASCENDA_SEMANTIC_CONSENT_SCOPE = exports.ASCENDA_PROVENANCE = exports.ASCENDA_CONSENT_SCOPE = exports.EVENT_WORKLOAD_CATEGORY = exports.COLLABORATION_EVENT_TYPES = exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = void 0;
|
|
586
|
+
exports.backendMetricKeys = exports.METRIC_KEYS = exports.ASCENDA_SEMANTIC_PROVENANCE = exports.ASCENDA_HISTORICAL_CONSENT_SCOPE = exports.ASCENDA_COLLABORATION_CONSENT_SCOPE = exports.ASCENDA_SEMANTIC_CONSENT_SCOPE = exports.ASCENDA_PROVENANCE = exports.ASCENDA_CONSENT_SCOPE = exports.EVENT_WORKLOAD_CATEGORY = exports.TOOL_EVENT_DELIVERED_STATUSES = exports.IDEMPOTENCY_KEY_MAX_LENGTH = exports.EVENT_METADATA_FIELDS = exports.COLLABORATION_EVENT_TYPES = exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = void 0;
|
|
529
587
|
exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = [
|
|
530
588
|
"approach_churn_detected",
|
|
531
589
|
"goal_drift_detected",
|
|
@@ -539,6 +597,39 @@ var require_out = __commonJS({
|
|
|
539
597
|
"review_given",
|
|
540
598
|
"pull_request_opened"
|
|
541
599
|
];
|
|
600
|
+
exports.EVENT_METADATA_FIELDS = [
|
|
601
|
+
"language",
|
|
602
|
+
"fileType",
|
|
603
|
+
"durationBucket",
|
|
604
|
+
"tokenPressureBucket",
|
|
605
|
+
"linesChangedBucket",
|
|
606
|
+
"commandClass",
|
|
607
|
+
"gitAction",
|
|
608
|
+
"milestoneKind",
|
|
609
|
+
"branchHash",
|
|
610
|
+
"autonomyMode",
|
|
611
|
+
"modelClass",
|
|
612
|
+
"modelId",
|
|
613
|
+
"userModified",
|
|
614
|
+
"outcome",
|
|
615
|
+
"trigger",
|
|
616
|
+
"promptClass",
|
|
617
|
+
"reason",
|
|
618
|
+
"afterHours",
|
|
619
|
+
"activity",
|
|
620
|
+
"message",
|
|
621
|
+
"host",
|
|
622
|
+
"toolName",
|
|
623
|
+
"simulated",
|
|
624
|
+
"relatedEventType",
|
|
625
|
+
"skillVersion",
|
|
626
|
+
"taskFingerprint",
|
|
627
|
+
"importKey",
|
|
628
|
+
"extractionId",
|
|
629
|
+
"importSchema"
|
|
630
|
+
];
|
|
631
|
+
exports.IDEMPOTENCY_KEY_MAX_LENGTH = 128;
|
|
632
|
+
exports.TOOL_EVENT_DELIVERED_STATUSES = ["accepted", "duplicate"];
|
|
542
633
|
exports.EVENT_WORKLOAD_CATEGORY = {
|
|
543
634
|
create_focus_session: "creation",
|
|
544
635
|
ai_prompt_submitted: "creation",
|
|
@@ -594,6 +685,98 @@ var require_out = __commonJS({
|
|
|
594
685
|
}
|
|
595
686
|
});
|
|
596
687
|
|
|
688
|
+
// ../packages/tool-kit/out/payload.js
|
|
689
|
+
var require_payload = __commonJS({
|
|
690
|
+
"../packages/tool-kit/out/payload.js"(exports) {
|
|
691
|
+
"use strict";
|
|
692
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
693
|
+
exports.mintIdempotencyKey = mintIdempotencyKey;
|
|
694
|
+
exports.getString = getString;
|
|
695
|
+
exports.getNumber = getNumber;
|
|
696
|
+
exports.getNested = getNested;
|
|
697
|
+
exports.getNestedString = getNestedString;
|
|
698
|
+
exports.getNestedNumber = getNestedNumber;
|
|
699
|
+
exports.inferOutcome = inferOutcome;
|
|
700
|
+
exports.outcomeForHook = outcomeForHook;
|
|
701
|
+
exports.looksLikeCorrection = looksLikeCorrection;
|
|
702
|
+
var node_crypto_1 = __require("node:crypto");
|
|
703
|
+
var tool_contract_1 = require_out();
|
|
704
|
+
function mintIdempotencyKey() {
|
|
705
|
+
const key = (0, node_crypto_1.randomUUID)();
|
|
706
|
+
if (key.length > tool_contract_1.IDEMPOTENCY_KEY_MAX_LENGTH)
|
|
707
|
+
throw new Error("idempotency key exceeds the wire limit");
|
|
708
|
+
return key;
|
|
709
|
+
}
|
|
710
|
+
function getString(input, keys) {
|
|
711
|
+
for (const key of keys) {
|
|
712
|
+
const value = input[key];
|
|
713
|
+
if (typeof value === "string" && value.trim())
|
|
714
|
+
return value;
|
|
715
|
+
}
|
|
716
|
+
return void 0;
|
|
717
|
+
}
|
|
718
|
+
function getNumber(input, keys) {
|
|
719
|
+
for (const key of keys) {
|
|
720
|
+
const value = input[key];
|
|
721
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
722
|
+
return value;
|
|
723
|
+
}
|
|
724
|
+
return void 0;
|
|
725
|
+
}
|
|
726
|
+
function getNested(input, path) {
|
|
727
|
+
let current = input;
|
|
728
|
+
for (const segment of path) {
|
|
729
|
+
if (!current || typeof current !== "object")
|
|
730
|
+
return void 0;
|
|
731
|
+
current = current[segment];
|
|
732
|
+
}
|
|
733
|
+
return current;
|
|
734
|
+
}
|
|
735
|
+
function getNestedString(input, paths) {
|
|
736
|
+
for (const path of paths) {
|
|
737
|
+
const value = getNested(input, path);
|
|
738
|
+
if (typeof value === "string" && value.trim())
|
|
739
|
+
return value;
|
|
740
|
+
}
|
|
741
|
+
return void 0;
|
|
742
|
+
}
|
|
743
|
+
function getNestedNumber(input, paths) {
|
|
744
|
+
for (const path of paths) {
|
|
745
|
+
const value = getNested(input, path);
|
|
746
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
747
|
+
return value;
|
|
748
|
+
}
|
|
749
|
+
return void 0;
|
|
750
|
+
}
|
|
751
|
+
function inferOutcome(input) {
|
|
752
|
+
const exitCode = getNumber(input, ["exitCode", "exit_code", "status"]) ?? getNestedNumber(input, [["tool_response", "exitCode"], ["tool_response", "exit_code"], ["result", "exitCode"], ["result", "exit_code"]]);
|
|
753
|
+
if (typeof exitCode === "number")
|
|
754
|
+
return exitCode === 0 ? "success" : "failure";
|
|
755
|
+
const error = getString(input, ["error", "errorMessage"]) ?? getNestedString(input, [["tool_response", "error"], ["result", "error"]]);
|
|
756
|
+
if (error)
|
|
757
|
+
return "failure";
|
|
758
|
+
return "unknown";
|
|
759
|
+
}
|
|
760
|
+
function outcomeForHook(hookName, input) {
|
|
761
|
+
if (hookName === "PostToolUseFailure") {
|
|
762
|
+
const interrupted = input["is_interrupt"] === true || getNested(input, ["tool_response", "interrupted"]) === true;
|
|
763
|
+
return interrupted ? "cancelled" : "failure";
|
|
764
|
+
}
|
|
765
|
+
if (hookName === "PostToolUse") {
|
|
766
|
+
if (getNested(input, ["tool_response", "interrupted"]) === true)
|
|
767
|
+
return "cancelled";
|
|
768
|
+
return "success";
|
|
769
|
+
}
|
|
770
|
+
return "unknown";
|
|
771
|
+
}
|
|
772
|
+
function looksLikeCorrection(text) {
|
|
773
|
+
if (!text)
|
|
774
|
+
return false;
|
|
775
|
+
return /\b(wrong|incorrect|try again|fix|not what i asked|that's not|that is not|redo|regenerate|you missed|doesn't work|does not work)\b/i.test(text);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
|
|
597
780
|
// ../packages/tool-kit/out/eventLog.js
|
|
598
781
|
var require_eventLog = __commonJS({
|
|
599
782
|
"../packages/tool-kit/out/eventLog.js"(exports) {
|
|
@@ -694,6 +877,7 @@ var require_http = __commonJS({
|
|
|
694
877
|
exports.postToolEvent = postToolEvent;
|
|
695
878
|
exports.postToolEventsBatch = postToolEventsBatch;
|
|
696
879
|
exports.parseIngestResponse = parseIngestResponse;
|
|
880
|
+
var tool_contract_1 = require_out();
|
|
697
881
|
var AscendaApiError = class extends Error {
|
|
698
882
|
status;
|
|
699
883
|
errorCode;
|
|
@@ -736,6 +920,35 @@ var require_http = __commonJS({
|
|
|
736
920
|
throw new AscendaApiError(response.status, void 0, await response.text());
|
|
737
921
|
return await response.json();
|
|
738
922
|
}
|
|
923
|
+
function isDeliveredStatus(value) {
|
|
924
|
+
return typeof value === "string" && tool_contract_1.TOOL_EVENT_DELIVERED_STATUSES.includes(value);
|
|
925
|
+
}
|
|
926
|
+
function readSuccessBody(body) {
|
|
927
|
+
let parsed;
|
|
928
|
+
try {
|
|
929
|
+
parsed = JSON.parse(body);
|
|
930
|
+
} catch {
|
|
931
|
+
return { duplicates: 0 };
|
|
932
|
+
}
|
|
933
|
+
if (!parsed || typeof parsed !== "object")
|
|
934
|
+
return { duplicates: 0 };
|
|
935
|
+
const single = parsed.status;
|
|
936
|
+
if (isDeliveredStatus(single))
|
|
937
|
+
return { duplicates: single === "duplicate" ? 1 : 0 };
|
|
938
|
+
const raw = parsed.results;
|
|
939
|
+
if (!Array.isArray(raw))
|
|
940
|
+
return { duplicates: 0 };
|
|
941
|
+
const results = [];
|
|
942
|
+
for (const item of raw) {
|
|
943
|
+
if (!item || typeof item !== "object")
|
|
944
|
+
continue;
|
|
945
|
+
const { index, status, reason } = item;
|
|
946
|
+
if (typeof index !== "number" || typeof status !== "string")
|
|
947
|
+
continue;
|
|
948
|
+
results.push({ index, status, ...typeof reason === "string" ? { reason } : {} });
|
|
949
|
+
}
|
|
950
|
+
return { duplicates: results.filter((item) => item.status === "duplicate").length, results };
|
|
951
|
+
}
|
|
739
952
|
function isRetryableStatus(status) {
|
|
740
953
|
return status === 408 || status === 429 || status !== void 0 && status >= 500 && status <= 599;
|
|
741
954
|
}
|
|
@@ -762,8 +975,20 @@ var require_http = __commonJS({
|
|
|
762
975
|
}
|
|
763
976
|
}
|
|
764
977
|
async function parseIngestResponse(response) {
|
|
765
|
-
if (response.ok)
|
|
766
|
-
|
|
978
|
+
if (response.ok) {
|
|
979
|
+
const outcome = { result: "accepted", httpStatus: response.status };
|
|
980
|
+
let read = { duplicates: 0 };
|
|
981
|
+
try {
|
|
982
|
+
read = readSuccessBody(await response.text());
|
|
983
|
+
} catch {
|
|
984
|
+
read = { duplicates: 0 };
|
|
985
|
+
}
|
|
986
|
+
return {
|
|
987
|
+
...outcome,
|
|
988
|
+
...read.duplicates > 0 ? { duplicates: read.duplicates } : {},
|
|
989
|
+
...read.results !== void 0 ? { results: read.results } : {}
|
|
990
|
+
};
|
|
991
|
+
}
|
|
767
992
|
const body = await response.text();
|
|
768
993
|
let errorCode;
|
|
769
994
|
try {
|
|
@@ -828,6 +1053,7 @@ var require_tokenStore = __commonJS({
|
|
|
828
1053
|
exports.ascendaHome = ascendaHome;
|
|
829
1054
|
exports.defaultTokenFilePath = defaultTokenFilePath2;
|
|
830
1055
|
exports.persistEventWriteToken = persistEventWriteToken2;
|
|
1056
|
+
exports.listPersistedToolInstallationIds = listPersistedToolInstallationIds;
|
|
831
1057
|
exports.readTokenFile = readTokenFile2;
|
|
832
1058
|
exports.sanitizeFilePart = sanitizeFilePart;
|
|
833
1059
|
var fs = __importStar(__require("fs"));
|
|
@@ -848,6 +1074,32 @@ var require_tokenStore = __commonJS({
|
|
|
848
1074
|
fs.chmodSync(tokenFilePath, 384);
|
|
849
1075
|
}
|
|
850
1076
|
}
|
|
1077
|
+
function listPersistedToolInstallationIds(toolType) {
|
|
1078
|
+
const prefix = `${sanitizeFilePart(toolType)}_`;
|
|
1079
|
+
const dir = path.join(ascendaHome(), "tokens");
|
|
1080
|
+
let names;
|
|
1081
|
+
try {
|
|
1082
|
+
names = fs.readdirSync(dir);
|
|
1083
|
+
} catch {
|
|
1084
|
+
return [];
|
|
1085
|
+
}
|
|
1086
|
+
const ids = [];
|
|
1087
|
+
for (const name of names.sort()) {
|
|
1088
|
+
if (!name.startsWith(prefix) || name.length === prefix.length)
|
|
1089
|
+
continue;
|
|
1090
|
+
const file = path.join(dir, name);
|
|
1091
|
+
try {
|
|
1092
|
+
if (!fs.statSync(file).isFile())
|
|
1093
|
+
continue;
|
|
1094
|
+
} catch {
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
if (readTokenFile2(file) === void 0)
|
|
1098
|
+
continue;
|
|
1099
|
+
ids.push(`${toolType}:${name.slice(prefix.length)}`);
|
|
1100
|
+
}
|
|
1101
|
+
return ids;
|
|
1102
|
+
}
|
|
851
1103
|
function readTokenFile2(tokenFilePath) {
|
|
852
1104
|
try {
|
|
853
1105
|
if (!fs.existsSync(tokenFilePath))
|
|
@@ -907,8 +1159,11 @@ var require_stateStore = __commonJS({
|
|
|
907
1159
|
}();
|
|
908
1160
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
909
1161
|
exports.defaultStateFilePath = defaultStateFilePath;
|
|
1162
|
+
exports.unresolvedToolInstallationId = unresolvedToolInstallationId;
|
|
1163
|
+
exports.unresolvedStateFilePath = unresolvedStateFilePath;
|
|
910
1164
|
exports.readCollectorState = readCollectorState;
|
|
911
1165
|
exports.recordSendOutcome = recordSendOutcome;
|
|
1166
|
+
exports.recordOutboxDiscard = recordOutboxDiscard;
|
|
912
1167
|
exports.shouldAnnounceFailure = shouldAnnounceFailure;
|
|
913
1168
|
exports.markFailureNotified = markFailureNotified;
|
|
914
1169
|
var fs = __importStar(__require("fs"));
|
|
@@ -920,6 +1175,12 @@ var require_stateStore = __commonJS({
|
|
|
920
1175
|
const base2 = dir ? dir : path.join(os.homedir(), ".ascenda", "state");
|
|
921
1176
|
return path.join(base2, `${(0, tokenStore_1.sanitizeFilePart)(toolInstallationId)}.json`);
|
|
922
1177
|
}
|
|
1178
|
+
function unresolvedToolInstallationId(toolType) {
|
|
1179
|
+
return `${toolType}:unresolved`;
|
|
1180
|
+
}
|
|
1181
|
+
function unresolvedStateFilePath(toolType) {
|
|
1182
|
+
return defaultStateFilePath(unresolvedToolInstallationId(toolType));
|
|
1183
|
+
}
|
|
923
1184
|
function readCollectorState(stateFilePath) {
|
|
924
1185
|
try {
|
|
925
1186
|
if (!fs.existsSync(stateFilePath))
|
|
@@ -952,7 +1213,28 @@ var require_stateStore = __commonJS({
|
|
|
952
1213
|
// the one already open. Carrying `notifiedFailingSince` across a
|
|
953
1214
|
// continuing episode is what keeps the notice to once per outage.
|
|
954
1215
|
...accepted ? {} : { failingSince: previous?.failingSince ?? now },
|
|
955
|
-
...accepted ? {} : previous?.notifiedFailingSince !== void 0 ? { notifiedFailingSince: previous.notifiedFailingSince } : {}
|
|
1216
|
+
...accepted ? {} : previous?.notifiedFailingSince !== void 0 ? { notifiedFailingSince: previous.notifiedFailingSince } : {},
|
|
1217
|
+
// Cumulative by design: a send outcome, success included, never erases
|
|
1218
|
+
// the record of what the outbox had to throw away.
|
|
1219
|
+
...previous?.outboxDiscarded !== void 0 ? { outboxDiscarded: previous.outboxDiscarded } : {}
|
|
1220
|
+
};
|
|
1221
|
+
writeStateFile(stateFilePath, next);
|
|
1222
|
+
return next;
|
|
1223
|
+
}
|
|
1224
|
+
function recordOutboxDiscard(stateFilePath, toolInstallationId, discard) {
|
|
1225
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1226
|
+
const previous = readCollectorState(stateFilePath);
|
|
1227
|
+
const next = {
|
|
1228
|
+
...previous ?? { lastAttemptAt: now, consecutiveFailures: 0 },
|
|
1229
|
+
toolInstallationId,
|
|
1230
|
+
lastOutcome: "outbox_discarded",
|
|
1231
|
+
outboxDiscarded: {
|
|
1232
|
+
total: (previous?.outboxDiscarded?.total ?? 0) + discard.count,
|
|
1233
|
+
lastAt: now,
|
|
1234
|
+
lastCount: discard.count,
|
|
1235
|
+
lastReasons: discard.reasons,
|
|
1236
|
+
...discard.oldestQueuedAt !== void 0 ? { lastOldestQueuedAt: discard.oldestQueuedAt } : {}
|
|
1237
|
+
}
|
|
956
1238
|
};
|
|
957
1239
|
writeStateFile(stateFilePath, next);
|
|
958
1240
|
return next;
|
|
@@ -992,19 +1274,241 @@ var require_stateStore = __commonJS({
|
|
|
992
1274
|
}
|
|
993
1275
|
});
|
|
994
1276
|
|
|
995
|
-
// ../packages/tool-kit/out/
|
|
996
|
-
var
|
|
997
|
-
"../packages/tool-kit/out/
|
|
1277
|
+
// ../packages/tool-kit/out/outbox.js
|
|
1278
|
+
var require_outbox = __commonJS({
|
|
1279
|
+
"../packages/tool-kit/out/outbox.js"(exports) {
|
|
998
1280
|
"use strict";
|
|
999
|
-
Object.
|
|
1000
|
-
|
|
1001
|
-
|
|
1281
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
1282
|
+
if (k2 === void 0) k2 = k;
|
|
1283
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
1284
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
1285
|
+
desc = { enumerable: true, get: function() {
|
|
1286
|
+
return m[k];
|
|
1287
|
+
} };
|
|
1288
|
+
}
|
|
1289
|
+
Object.defineProperty(o, k2, desc);
|
|
1290
|
+
} : function(o, m, k, k2) {
|
|
1291
|
+
if (k2 === void 0) k2 = k;
|
|
1292
|
+
o[k2] = m[k];
|
|
1293
|
+
});
|
|
1294
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
1295
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
1296
|
+
} : function(o, v) {
|
|
1297
|
+
o["default"] = v;
|
|
1298
|
+
});
|
|
1299
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
|
|
1300
|
+
var ownKeys = function(o) {
|
|
1301
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
1302
|
+
var ar = [];
|
|
1303
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
1304
|
+
return ar;
|
|
1305
|
+
};
|
|
1306
|
+
return ownKeys(o);
|
|
1307
|
+
};
|
|
1308
|
+
return function(mod) {
|
|
1309
|
+
if (mod && mod.__esModule) return mod;
|
|
1310
|
+
var result = {};
|
|
1311
|
+
if (mod != null) {
|
|
1312
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
1313
|
+
}
|
|
1314
|
+
__setModuleDefault(result, mod);
|
|
1315
|
+
return result;
|
|
1316
|
+
};
|
|
1317
|
+
}();
|
|
1318
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1319
|
+
exports.DEFAULT_OUTBOX_DRAIN_BATCH_SIZE = exports.DEFAULT_OUTBOX_MAX_AGE_MS = exports.DEFAULT_OUTBOX_MAX_ENTRIES = exports.OUTBOX_DRAIN_ENV_VAR = void 0;
|
|
1320
|
+
exports.outboxDrainEnabled = outboxDrainEnabled;
|
|
1321
|
+
exports.defaultOutboxFilePath = defaultOutboxFilePath;
|
|
1322
|
+
exports.appendToOutbox = appendToOutbox;
|
|
1323
|
+
exports.readOutboxSummary = readOutboxSummary;
|
|
1324
|
+
exports.claimOutbox = claimOutbox;
|
|
1325
|
+
exports.enforceOutboxBounds = enforceOutboxBounds;
|
|
1326
|
+
var fs = __importStar(__require("fs"));
|
|
1327
|
+
var path = __importStar(__require("path"));
|
|
1328
|
+
var stateStore_1 = require_stateStore();
|
|
1329
|
+
var tokenStore_1 = require_tokenStore();
|
|
1330
|
+
exports.OUTBOX_DRAIN_ENV_VAR = "ASCENDA_OUTBOX_DRAIN";
|
|
1331
|
+
exports.DEFAULT_OUTBOX_MAX_ENTRIES = 1e4;
|
|
1332
|
+
exports.DEFAULT_OUTBOX_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
1333
|
+
exports.DEFAULT_OUTBOX_DRAIN_BATCH_SIZE = 100;
|
|
1334
|
+
var ORPHANED_CLAIM_AGE_MS = 6e4;
|
|
1335
|
+
var CLAIM_SUFFIX = ".draining";
|
|
1336
|
+
function outboxDrainEnabled(env = process.env) {
|
|
1337
|
+
const value = env[exports.OUTBOX_DRAIN_ENV_VAR]?.trim().toLowerCase();
|
|
1338
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
1339
|
+
}
|
|
1340
|
+
function defaultOutboxFilePath(toolInstallationId) {
|
|
1341
|
+
const dir = path.dirname((0, stateStore_1.defaultStateFilePath)(toolInstallationId));
|
|
1342
|
+
return path.join(dir, `${(0, tokenStore_1.sanitizeFilePart)(toolInstallationId)}.outbox.jsonl`);
|
|
1343
|
+
}
|
|
1344
|
+
function appendToOutbox(outboxFilePath, payload, now = /* @__PURE__ */ new Date()) {
|
|
1345
|
+
try {
|
|
1346
|
+
const dir = path.dirname(outboxFilePath);
|
|
1347
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
1348
|
+
const entry = { queuedAt: now.toISOString(), payload };
|
|
1349
|
+
fs.appendFileSync(outboxFilePath, `${JSON.stringify(entry)}
|
|
1350
|
+
`, { encoding: "utf8", mode: 384 });
|
|
1351
|
+
if (process.platform !== "win32")
|
|
1352
|
+
fs.chmodSync(outboxFilePath, 384);
|
|
1353
|
+
return true;
|
|
1354
|
+
} catch {
|
|
1355
|
+
return false;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
function readOutboxSummary(outboxFilePath) {
|
|
1359
|
+
const files = [outboxFilePath, ...listClaimFiles(outboxFilePath)].filter((file) => fs.existsSync(file));
|
|
1360
|
+
if (files.length === 0)
|
|
1361
|
+
return void 0;
|
|
1362
|
+
let depth = 0;
|
|
1363
|
+
let unreadableLines = 0;
|
|
1364
|
+
let oldestQueuedAt;
|
|
1365
|
+
for (const file of files) {
|
|
1366
|
+
const { entries, unreadable } = readEntries(file);
|
|
1367
|
+
depth += entries.length;
|
|
1368
|
+
unreadableLines += unreadable;
|
|
1369
|
+
for (const entry of entries) {
|
|
1370
|
+
if (oldestQueuedAt === void 0 || entry.queuedAt < oldestQueuedAt)
|
|
1371
|
+
oldestQueuedAt = entry.queuedAt;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return { depth, unreadableLines, ...oldestQueuedAt !== void 0 ? { oldestQueuedAt } : {} };
|
|
1375
|
+
}
|
|
1376
|
+
function claimOutbox(outboxFilePath, now = Date.now()) {
|
|
1377
|
+
const claimPath = `${outboxFilePath}.${process.pid}${CLAIM_SUFFIX}`;
|
|
1378
|
+
const claimed = [];
|
|
1379
|
+
try {
|
|
1380
|
+
fs.renameSync(outboxFilePath, claimPath);
|
|
1381
|
+
claimed.push(claimPath);
|
|
1382
|
+
} catch {
|
|
1383
|
+
}
|
|
1384
|
+
let orphanIndex = 0;
|
|
1385
|
+
for (const orphan of listClaimFiles(outboxFilePath)) {
|
|
1386
|
+
if (claimed.includes(orphan))
|
|
1387
|
+
continue;
|
|
1388
|
+
try {
|
|
1389
|
+
if (now - fs.statSync(orphan).mtimeMs < ORPHANED_CLAIM_AGE_MS)
|
|
1390
|
+
continue;
|
|
1391
|
+
const mine = `${claimPath}.${orphanIndex++}`;
|
|
1392
|
+
fs.renameSync(orphan, mine);
|
|
1393
|
+
claimed.push(mine);
|
|
1394
|
+
} catch {
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
if (claimed.length === 0)
|
|
1398
|
+
return void 0;
|
|
1399
|
+
const entries = [];
|
|
1400
|
+
let unreadable = 0;
|
|
1401
|
+
for (const file of claimed) {
|
|
1402
|
+
const read = readEntries(file);
|
|
1403
|
+
entries.push(...read.entries);
|
|
1404
|
+
unreadable += read.unreadable;
|
|
1405
|
+
}
|
|
1406
|
+
entries.sort((a, b) => a.queuedAt < b.queuedAt ? -1 : a.queuedAt > b.queuedAt ? 1 : 0);
|
|
1407
|
+
let released = false;
|
|
1408
|
+
return {
|
|
1409
|
+
entries,
|
|
1410
|
+
unreadable,
|
|
1411
|
+
release(remainder) {
|
|
1412
|
+
if (released)
|
|
1413
|
+
return;
|
|
1414
|
+
released = true;
|
|
1415
|
+
if (remainder.length > 0) {
|
|
1416
|
+
try {
|
|
1417
|
+
fs.mkdirSync(path.dirname(outboxFilePath), { recursive: true, mode: 448 });
|
|
1418
|
+
fs.appendFileSync(outboxFilePath, remainder.map((entry) => `${JSON.stringify(entry)}
|
|
1419
|
+
`).join(""), { encoding: "utf8", mode: 384 });
|
|
1420
|
+
if (process.platform !== "win32")
|
|
1421
|
+
fs.chmodSync(outboxFilePath, 384);
|
|
1422
|
+
} catch {
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
for (const file of claimed) {
|
|
1427
|
+
try {
|
|
1428
|
+
fs.unlinkSync(file);
|
|
1429
|
+
} catch {
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
function enforceOutboxBounds(entries, bounds, now = Date.now()) {
|
|
1436
|
+
const reasons = {};
|
|
1437
|
+
let oldestQueuedAt;
|
|
1438
|
+
const cutoff = new Date(now - bounds.maxAgeMs).toISOString();
|
|
1439
|
+
const fresh = [];
|
|
1440
|
+
for (const entry of entries) {
|
|
1441
|
+
if (entry.queuedAt < cutoff) {
|
|
1442
|
+
reasons.age = (reasons.age ?? 0) + 1;
|
|
1443
|
+
if (oldestQueuedAt === void 0 || entry.queuedAt < oldestQueuedAt)
|
|
1444
|
+
oldestQueuedAt = entry.queuedAt;
|
|
1445
|
+
} else {
|
|
1446
|
+
fresh.push(entry);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
const excess = Math.max(0, fresh.length - bounds.maxEntries);
|
|
1450
|
+
if (excess > 0) {
|
|
1451
|
+
reasons.count = excess;
|
|
1452
|
+
const first = fresh[0]?.queuedAt;
|
|
1453
|
+
if (first !== void 0 && (oldestQueuedAt === void 0 || first < oldestQueuedAt))
|
|
1454
|
+
oldestQueuedAt = first;
|
|
1455
|
+
}
|
|
1456
|
+
const kept = excess > 0 ? fresh.slice(excess) : fresh;
|
|
1457
|
+
const count = Object.values(reasons).reduce((sum, n) => sum + (n ?? 0), 0);
|
|
1458
|
+
return { kept, discarded: { count, reasons, ...oldestQueuedAt !== void 0 ? { oldestQueuedAt } : {} } };
|
|
1459
|
+
}
|
|
1460
|
+
function listClaimFiles(outboxFilePath) {
|
|
1461
|
+
const dir = path.dirname(outboxFilePath);
|
|
1462
|
+
const prefix = `${path.basename(outboxFilePath)}.`;
|
|
1463
|
+
try {
|
|
1464
|
+
return fs.readdirSync(dir).filter((name) => name.startsWith(prefix) && name.includes(CLAIM_SUFFIX)).map((name) => path.join(dir, name)).sort();
|
|
1465
|
+
} catch {
|
|
1466
|
+
return [];
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
function readEntries(file) {
|
|
1470
|
+
let raw;
|
|
1471
|
+
try {
|
|
1472
|
+
raw = fs.readFileSync(file, "utf8");
|
|
1473
|
+
} catch {
|
|
1474
|
+
return { entries: [], unreadable: 0 };
|
|
1475
|
+
}
|
|
1476
|
+
const entries = [];
|
|
1477
|
+
let unreadable = 0;
|
|
1478
|
+
for (const line of raw.split("\n")) {
|
|
1479
|
+
if (!line.trim())
|
|
1480
|
+
continue;
|
|
1481
|
+
try {
|
|
1482
|
+
const parsed = JSON.parse(line);
|
|
1483
|
+
if (!parsed || typeof parsed !== "object" || typeof parsed.queuedAt !== "string" || !parsed.payload || typeof parsed.payload !== "object") {
|
|
1484
|
+
unreadable += 1;
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
entries.push({ queuedAt: parsed.queuedAt, payload: parsed.payload });
|
|
1488
|
+
} catch {
|
|
1489
|
+
unreadable += 1;
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return { entries, unreadable };
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
// ../packages/tool-kit/out/eventSender.js
|
|
1498
|
+
var require_eventSender = __commonJS({
|
|
1499
|
+
"../packages/tool-kit/out/eventSender.js"(exports) {
|
|
1500
|
+
"use strict";
|
|
1501
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1502
|
+
exports.AscendaEventSender = exports.AscendaSemanticEventError = void 0;
|
|
1503
|
+
exports.buildEventPayload = buildEventPayload;
|
|
1002
1504
|
var afterHours_1 = require_afterHours();
|
|
1003
1505
|
var tool_contract_1 = require_out();
|
|
1004
1506
|
var eventLog_1 = require_eventLog();
|
|
1005
1507
|
var http_1 = require_http();
|
|
1508
|
+
var outbox_1 = require_outbox();
|
|
1006
1509
|
var tokenStore_1 = require_tokenStore();
|
|
1007
1510
|
var stateStore_1 = require_stateStore();
|
|
1511
|
+
var payload_1 = require_payload();
|
|
1008
1512
|
var AscendaSemanticEventError = class extends Error {
|
|
1009
1513
|
constructor(message) {
|
|
1010
1514
|
super(message);
|
|
@@ -1017,6 +1521,7 @@ var require_eventSender = __commonJS({
|
|
|
1017
1521
|
toolInstallationId: identity.toolInstallationId,
|
|
1018
1522
|
source: identity.source,
|
|
1019
1523
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1524
|
+
idempotencyKey: (0, payload_1.mintIdempotencyKey)(),
|
|
1020
1525
|
utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
|
|
1021
1526
|
sessionId: identity.sessionId ?? void 0,
|
|
1022
1527
|
workspaceHash: identity.workspaceHash ?? void 0,
|
|
@@ -1034,6 +1539,9 @@ var require_eventSender = __commonJS({
|
|
|
1034
1539
|
config;
|
|
1035
1540
|
eventWriteToken;
|
|
1036
1541
|
lastState;
|
|
1542
|
+
lastDrain;
|
|
1543
|
+
/** One outbox pass per sender, i.e. per hook process. The hook is on the user's critical path. */
|
|
1544
|
+
outboxServiced = false;
|
|
1037
1545
|
constructor(config) {
|
|
1038
1546
|
this.config = config;
|
|
1039
1547
|
this.eventWriteToken = config.eventWriteToken;
|
|
@@ -1072,6 +1580,7 @@ var require_eventSender = __commonJS({
|
|
|
1072
1580
|
source: this.config.source,
|
|
1073
1581
|
eventType: mapped.eventType,
|
|
1074
1582
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1583
|
+
idempotencyKey: (0, payload_1.mintIdempotencyKey)(),
|
|
1075
1584
|
utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
|
|
1076
1585
|
severity: "low",
|
|
1077
1586
|
sessionId: this.config.sessionId ?? void 0,
|
|
@@ -1102,6 +1611,7 @@ var require_eventSender = __commonJS({
|
|
|
1102
1611
|
source: this.config.source,
|
|
1103
1612
|
eventType: mapped.eventType,
|
|
1104
1613
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1614
|
+
idempotencyKey: (0, payload_1.mintIdempotencyKey)(),
|
|
1105
1615
|
utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
|
|
1106
1616
|
severity: "low",
|
|
1107
1617
|
sessionId: this.config.sessionId ?? void 0,
|
|
@@ -1120,15 +1630,30 @@ var require_eventSender = __commonJS({
|
|
|
1120
1630
|
* deliberate: Claude Code, Codex, the GitHub collector and the MCP server all
|
|
1121
1631
|
* send through this method, and the defect being fixed showed up in three
|
|
1122
1632
|
* separate components because each was left to notice its own failures.
|
|
1633
|
+
*
|
|
1634
|
+
* The outbox is serviced first, once per process. If that pass just watched
|
|
1635
|
+
* the ingest door refuse a batch, the live event is not offered to the same
|
|
1636
|
+
* door a second time in the same instant: it inherits the pass's outcome,
|
|
1637
|
+
* and a retryable one puts it straight in the queue. That is what keeps a
|
|
1638
|
+
* hook during an outage to one bounded round trip instead of three.
|
|
1123
1639
|
*/
|
|
1124
1640
|
async post(payload) {
|
|
1125
|
-
const
|
|
1641
|
+
const halted = await this.serviceOutbox();
|
|
1642
|
+
let outcome;
|
|
1643
|
+
let queued = false;
|
|
1644
|
+
if (halted) {
|
|
1645
|
+
outcome = halted;
|
|
1646
|
+
queued = this.isRetryable(outcome) && this.enqueue(payload);
|
|
1647
|
+
} else {
|
|
1648
|
+
outcome = await this.attempt(payload);
|
|
1649
|
+
queued = this.isRetryable(outcome) && this.enqueue(payload);
|
|
1650
|
+
}
|
|
1126
1651
|
this.lastState = (0, stateStore_1.recordSendOutcome)(this.stateFilePath(), this.config.toolInstallationId, outcome.result, {
|
|
1127
1652
|
httpStatus: outcome.httpStatus,
|
|
1128
1653
|
errorCode: outcome.errorCode,
|
|
1129
|
-
detail: outcome.detail
|
|
1654
|
+
detail: queued ? withNote(outcome.detail, "queued in outbox") : outcome.detail
|
|
1130
1655
|
});
|
|
1131
|
-
this.log(payload, outcome.result);
|
|
1656
|
+
this.log(payload, outcome.result, queued ? "queued" : void 0);
|
|
1132
1657
|
return outcome.result;
|
|
1133
1658
|
}
|
|
1134
1659
|
/**
|
|
@@ -1137,6 +1662,15 @@ var require_eventSender = __commonJS({
|
|
|
1137
1662
|
* error gets one retry, because the common cases (a restarting instance, a
|
|
1138
1663
|
* proxy blip, a 429) clear in well under a second and the alternative is
|
|
1139
1664
|
* losing the event outright.
|
|
1665
|
+
*
|
|
1666
|
+
* Both recoveries resend the same `payload` object, so the `idempotencyKey`
|
|
1667
|
+
* minted at construction is what the server sees on every attempt. That is
|
|
1668
|
+
* what lets a retry of a request the server actually processed (a timeout
|
|
1669
|
+
* after the write, a 502 from a proxy in front of a 200) come back
|
|
1670
|
+
* `duplicate` instead of landing twice. Never rebuild the payload here.
|
|
1671
|
+
*
|
|
1672
|
+
* When the retry fails too, the caller queues the payload: anything longer
|
|
1673
|
+
* than the pause here is the outbox's job, not another in-process wait.
|
|
1140
1674
|
*/
|
|
1141
1675
|
async attempt(payload) {
|
|
1142
1676
|
const outcome = await (0, http_1.postToolEvent)(this.config.apiBaseUrl, this.eventWriteToken, payload, this.signal());
|
|
@@ -1145,12 +1679,138 @@ var require_eventSender = __commonJS({
|
|
|
1145
1679
|
return outcome;
|
|
1146
1680
|
return (0, http_1.postToolEvent)(this.config.apiBaseUrl, this.eventWriteToken, payload, this.signal());
|
|
1147
1681
|
}
|
|
1148
|
-
if (
|
|
1682
|
+
if (this.isRetryable(outcome)) {
|
|
1149
1683
|
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
1150
1684
|
return (0, http_1.postToolEvent)(this.config.apiBaseUrl, this.eventWriteToken, payload, this.signal());
|
|
1151
1685
|
}
|
|
1152
1686
|
return outcome;
|
|
1153
1687
|
}
|
|
1688
|
+
/** A failure that never reached a verdict. Replaying can change the answer. */
|
|
1689
|
+
isRetryable(outcome) {
|
|
1690
|
+
return outcome.result === "transport_error" && (outcome.httpStatus === void 0 || (0, http_1.isRetryableStatus)(outcome.httpStatus));
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* Keeps a refused payload for a later drain. Returns whether it is now on
|
|
1694
|
+
* disk; when it is not (read-only home, full disk) the event is lost and the
|
|
1695
|
+
* journal's detail says so instead of implying it was kept.
|
|
1696
|
+
*/
|
|
1697
|
+
enqueue(payload) {
|
|
1698
|
+
return (0, outbox_1.appendToOutbox)(this.outboxFilePath(), payload);
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* One pass over the outbox: claim it, apply the bounds, and — when sending
|
|
1702
|
+
* is enabled — offer one batch, oldest first, to the batch door.
|
|
1703
|
+
*
|
|
1704
|
+
* Entries are deleted on `accepted` or `duplicate`, decided on `status`
|
|
1705
|
+
* alone; `reason` is for a person reading their logs. A per-item `rejected`
|
|
1706
|
+
* is a verdict, and replaying a verdict cannot change it, so those are
|
|
1707
|
+
* discarded and journaled rather than kept forever. A whole-batch
|
|
1708
|
+
* `validation_failed` is the same verdict for every item. Anything else
|
|
1709
|
+
* stops the pass with everything still on disk, and is returned so the live
|
|
1710
|
+
* send can skip a door that just refused.
|
|
1711
|
+
*
|
|
1712
|
+
* Never loops, never backs off, never sends more than one batch: the next
|
|
1713
|
+
* hook invocation is usually seconds away, and a hook sitting in a retry
|
|
1714
|
+
* loop delays the tool call the user is waiting on.
|
|
1715
|
+
*/
|
|
1716
|
+
async serviceOutbox() {
|
|
1717
|
+
if (this.outboxServiced)
|
|
1718
|
+
return void 0;
|
|
1719
|
+
this.outboxServiced = true;
|
|
1720
|
+
const sendEnabled = this.config.outboxDrain ?? (0, outbox_1.outboxDrainEnabled)();
|
|
1721
|
+
const claimed = (0, outbox_1.claimOutbox)(this.outboxFilePath());
|
|
1722
|
+
if (!claimed) {
|
|
1723
|
+
this.lastDrain = { found: 0, discarded: 0, delivered: 0, remaining: 0, sendEnabled };
|
|
1724
|
+
return void 0;
|
|
1725
|
+
}
|
|
1726
|
+
const found = claimed.entries.length + claimed.unreadable;
|
|
1727
|
+
const { kept, discarded } = (0, outbox_1.enforceOutboxBounds)(claimed.entries, {
|
|
1728
|
+
maxEntries: this.config.outboxMaxEntries ?? outbox_1.DEFAULT_OUTBOX_MAX_ENTRIES,
|
|
1729
|
+
maxAgeMs: this.config.outboxMaxAgeMs ?? outbox_1.DEFAULT_OUTBOX_MAX_AGE_MS
|
|
1730
|
+
});
|
|
1731
|
+
if (claimed.unreadable > 0) {
|
|
1732
|
+
discarded.count += claimed.unreadable;
|
|
1733
|
+
discarded.reasons.unreadable = claimed.unreadable;
|
|
1734
|
+
}
|
|
1735
|
+
let discardedTotal = this.journalDiscard(discarded);
|
|
1736
|
+
if (!sendEnabled || kept.length === 0) {
|
|
1737
|
+
claimed.release(kept);
|
|
1738
|
+
this.lastDrain = { found, discarded: discardedTotal, delivered: 0, remaining: kept.length, sendEnabled };
|
|
1739
|
+
return void 0;
|
|
1740
|
+
}
|
|
1741
|
+
const batchSize = this.config.outboxDrainBatchSize ?? outbox_1.DEFAULT_OUTBOX_DRAIN_BATCH_SIZE;
|
|
1742
|
+
const batch = kept.slice(0, batchSize);
|
|
1743
|
+
const rest = kept.slice(batchSize);
|
|
1744
|
+
const outcome = await this.attemptBatch(batch.map((entry) => entry.payload));
|
|
1745
|
+
let delivered = [];
|
|
1746
|
+
let rejected = [];
|
|
1747
|
+
let undecided = [];
|
|
1748
|
+
let halted;
|
|
1749
|
+
if (outcome.result === "accepted") {
|
|
1750
|
+
if (outcome.results === void 0) {
|
|
1751
|
+
delivered = batch;
|
|
1752
|
+
} else {
|
|
1753
|
+
const byIndex = new Map(outcome.results.map((item) => [item.index, item.status]));
|
|
1754
|
+
for (const [index, entry] of batch.entries()) {
|
|
1755
|
+
const status = byIndex.get(index);
|
|
1756
|
+
if (status !== void 0 && tool_contract_1.TOOL_EVENT_DELIVERED_STATUSES.includes(status))
|
|
1757
|
+
delivered.push(entry);
|
|
1758
|
+
else if (status === "rejected")
|
|
1759
|
+
rejected.push(entry);
|
|
1760
|
+
else
|
|
1761
|
+
undecided.push(entry);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
} else if (outcome.result === "validation_failed") {
|
|
1765
|
+
rejected = batch;
|
|
1766
|
+
} else {
|
|
1767
|
+
undecided = batch;
|
|
1768
|
+
halted = outcome;
|
|
1769
|
+
}
|
|
1770
|
+
if (rejected.length > 0) {
|
|
1771
|
+
discardedTotal += this.journalDiscard({ count: rejected.length, reasons: { rejected: rejected.length }, oldestQueuedAt: rejected[0]?.queuedAt });
|
|
1772
|
+
}
|
|
1773
|
+
if (!halted) {
|
|
1774
|
+
this.lastState = (0, stateStore_1.recordSendOutcome)(this.stateFilePath(), this.config.toolInstallationId, outcome.result, {
|
|
1775
|
+
httpStatus: outcome.httpStatus,
|
|
1776
|
+
errorCode: outcome.errorCode,
|
|
1777
|
+
detail: withNote(outcome.detail, `outbox drain: ${delivered.length} delivered`)
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
for (const entry of delivered)
|
|
1781
|
+
this.log(entry.payload, "accepted", "drained");
|
|
1782
|
+
const remainder = [...undecided, ...rest];
|
|
1783
|
+
claimed.release(remainder);
|
|
1784
|
+
this.lastDrain = {
|
|
1785
|
+
found,
|
|
1786
|
+
discarded: discardedTotal,
|
|
1787
|
+
delivered: delivered.length,
|
|
1788
|
+
remaining: remainder.length,
|
|
1789
|
+
sendEnabled,
|
|
1790
|
+
...halted ? { halted: halted.result } : {}
|
|
1791
|
+
};
|
|
1792
|
+
return halted;
|
|
1793
|
+
}
|
|
1794
|
+
/** The batch door, with the same single token renewal as the live path and no in-process retry. */
|
|
1795
|
+
async attemptBatch(payloads) {
|
|
1796
|
+
const outcome = await (0, http_1.postToolEventsBatch)(this.config.apiBaseUrl, this.eventWriteToken, payloads, this.signal());
|
|
1797
|
+
if (outcome.result !== "auth_failed")
|
|
1798
|
+
return outcome;
|
|
1799
|
+
if (!await this.renewEventToken())
|
|
1800
|
+
return outcome;
|
|
1801
|
+
return (0, http_1.postToolEventsBatch)(this.config.apiBaseUrl, this.eventWriteToken, payloads, this.signal());
|
|
1802
|
+
}
|
|
1803
|
+
journalDiscard(discard) {
|
|
1804
|
+
if (discard.count === 0)
|
|
1805
|
+
return 0;
|
|
1806
|
+
const reasons = discard.reasons;
|
|
1807
|
+
this.lastState = (0, stateStore_1.recordOutboxDiscard)(this.stateFilePath(), this.config.toolInstallationId, {
|
|
1808
|
+
count: discard.count,
|
|
1809
|
+
reasons,
|
|
1810
|
+
oldestQueuedAt: discard.oldestQueuedAt
|
|
1811
|
+
});
|
|
1812
|
+
return discard.count;
|
|
1813
|
+
}
|
|
1154
1814
|
/**
|
|
1155
1815
|
* The state written by the most recent send, so a caller can decide whether
|
|
1156
1816
|
* to surface a one-time notice without re-reading the journal it just wrote.
|
|
@@ -1158,10 +1818,16 @@ var require_eventSender = __commonJS({
|
|
|
1158
1818
|
get state() {
|
|
1159
1819
|
return this.lastState;
|
|
1160
1820
|
}
|
|
1821
|
+
/** What this sender's one outbox pass did; undefined before the first send. */
|
|
1822
|
+
get drain() {
|
|
1823
|
+
return this.lastDrain;
|
|
1824
|
+
}
|
|
1161
1825
|
stateFilePath() {
|
|
1162
1826
|
return this.config.stateFilePath ?? (0, stateStore_1.defaultStateFilePath)(this.config.toolInstallationId);
|
|
1163
1827
|
}
|
|
1164
|
-
|
|
1828
|
+
outboxFilePath() {
|
|
1829
|
+
return this.config.outboxFilePath ?? (0, outbox_1.defaultOutboxFilePath)(this.config.toolInstallationId);
|
|
1830
|
+
}
|
|
1165
1831
|
/**
|
|
1166
1832
|
* Every send path funnels through {@link post}, so semantic and
|
|
1167
1833
|
* collaboration signals are logged on the same terms as host events — the
|
|
@@ -1171,12 +1837,13 @@ var require_eventSender = __commonJS({
|
|
|
1171
1837
|
* It is now `transport_error` through the ordinary path, because the
|
|
1172
1838
|
* transport returns that outcome instead of throwing.
|
|
1173
1839
|
*/
|
|
1174
|
-
log(payload, delivery) {
|
|
1840
|
+
log(payload, delivery, outbox) {
|
|
1175
1841
|
const logFile = this.config.eventLogFile === void 0 ? (0, eventLog_1.resolveEventLogPath)() : this.config.eventLogFile;
|
|
1176
1842
|
if (!logFile)
|
|
1177
1843
|
return;
|
|
1178
|
-
(0, eventLog_1.appendEventLog)(logFile, { loggedAt: (/* @__PURE__ */ new Date()).toISOString(), delivery, payload });
|
|
1844
|
+
(0, eventLog_1.appendEventLog)(logFile, { loggedAt: (/* @__PURE__ */ new Date()).toISOString(), delivery, payload, ...outbox ? { outbox } : {} });
|
|
1179
1845
|
}
|
|
1846
|
+
/** Never throws: a renewal that errors is a failed renewal, not a failed turn. */
|
|
1180
1847
|
async renewEventToken() {
|
|
1181
1848
|
try {
|
|
1182
1849
|
const renewed = await (0, http_1.renewToolToken)(this.config.apiBaseUrl, this.eventWriteToken, this.signal());
|
|
@@ -1194,6 +1861,9 @@ var require_eventSender = __commonJS({
|
|
|
1194
1861
|
}
|
|
1195
1862
|
};
|
|
1196
1863
|
exports.AscendaEventSender = AscendaEventSender2;
|
|
1864
|
+
function withNote(detail, note) {
|
|
1865
|
+
return detail ? `${detail} (${note})` : note;
|
|
1866
|
+
}
|
|
1197
1867
|
}
|
|
1198
1868
|
});
|
|
1199
1869
|
|
|
@@ -1272,72 +1942,335 @@ var require_contextRegistry = __commonJS({
|
|
|
1272
1942
|
}
|
|
1273
1943
|
return upsert(updates, options);
|
|
1274
1944
|
}
|
|
1275
|
-
function recordWorkContextAlias(
|
|
1276
|
-
if (!
|
|
1945
|
+
function recordWorkContextAlias(hash, label, observedPath, options) {
|
|
1946
|
+
if (!hash || !label)
|
|
1277
1947
|
return false;
|
|
1278
|
-
return upsert([{ hash
|
|
1948
|
+
return upsert([{ hash, kind: "alias", label, observedPath: observedPath ?? null }], options);
|
|
1279
1949
|
}
|
|
1280
1950
|
function upsert(updates, options) {
|
|
1281
1951
|
if (updates.length === 0)
|
|
1282
1952
|
return false;
|
|
1283
1953
|
try {
|
|
1284
|
-
const registryFilePath = options?.registryFilePath ?? workContextRegistryFilePath();
|
|
1285
|
-
const nowIso = (options?.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
1286
|
-
const registry = readWorkContextRegistry(registryFilePath);
|
|
1287
|
-
let dirty = false;
|
|
1288
|
-
for (const update of updates) {
|
|
1289
|
-
const existing = registry.contexts[update.hash];
|
|
1290
|
-
if (!existing) {
|
|
1291
|
-
registry.contexts[update.hash] = {
|
|
1292
|
-
kind: update.kind,
|
|
1293
|
-
label: update.label,
|
|
1294
|
-
paths: update.observedPath ? [update.observedPath] : [],
|
|
1295
|
-
firstSeenAt: nowIso,
|
|
1296
|
-
lastSeenAt: nowIso
|
|
1297
|
-
};
|
|
1298
|
-
dirty = true;
|
|
1954
|
+
const registryFilePath = options?.registryFilePath ?? workContextRegistryFilePath();
|
|
1955
|
+
const nowIso = (options?.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
1956
|
+
const registry = readWorkContextRegistry(registryFilePath);
|
|
1957
|
+
let dirty = false;
|
|
1958
|
+
for (const update of updates) {
|
|
1959
|
+
const existing = registry.contexts[update.hash];
|
|
1960
|
+
if (!existing) {
|
|
1961
|
+
registry.contexts[update.hash] = {
|
|
1962
|
+
kind: update.kind,
|
|
1963
|
+
label: update.label,
|
|
1964
|
+
paths: update.observedPath ? [update.observedPath] : [],
|
|
1965
|
+
firstSeenAt: nowIso,
|
|
1966
|
+
lastSeenAt: nowIso
|
|
1967
|
+
};
|
|
1968
|
+
dirty = true;
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
if (existing.kind === "alias" && update.kind !== "alias") {
|
|
1972
|
+
existing.kind = update.kind;
|
|
1973
|
+
dirty = true;
|
|
1974
|
+
}
|
|
1975
|
+
if (existing.label !== update.label && update.kind !== "alias") {
|
|
1976
|
+
existing.label = update.label;
|
|
1977
|
+
dirty = true;
|
|
1978
|
+
}
|
|
1979
|
+
if (update.observedPath && !existing.paths.includes(update.observedPath)) {
|
|
1980
|
+
if (existing.paths.length < MAX_PATHS_PER_ENTRY)
|
|
1981
|
+
existing.paths.push(update.observedPath);
|
|
1982
|
+
dirty = true;
|
|
1983
|
+
}
|
|
1984
|
+
if (dayOf(existing.lastSeenAt) !== dayOf(nowIso)) {
|
|
1985
|
+
existing.lastSeenAt = nowIso;
|
|
1986
|
+
dirty = true;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
if (!dirty)
|
|
1990
|
+
return false;
|
|
1991
|
+
writeRegistry(registryFilePath, registry);
|
|
1992
|
+
return true;
|
|
1993
|
+
} catch {
|
|
1994
|
+
return false;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
function dayOf(iso) {
|
|
1998
|
+
return iso.slice(0, 10);
|
|
1999
|
+
}
|
|
2000
|
+
function writeRegistry(registryFilePath, registry) {
|
|
2001
|
+
const dir = path.dirname(registryFilePath);
|
|
2002
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2003
|
+
const tmp = `${registryFilePath}.${process.pid}.tmp`;
|
|
2004
|
+
fs.writeFileSync(tmp, `${JSON.stringify(registry, null, 2)}
|
|
2005
|
+
`, { encoding: "utf8", mode: 384 });
|
|
2006
|
+
fs.renameSync(tmp, registryFilePath);
|
|
2007
|
+
if (process.platform !== "win32") {
|
|
2008
|
+
fs.chmodSync(registryFilePath, 384);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
|
|
2014
|
+
// ../packages/tool-kit/out/credentials.js
|
|
2015
|
+
var require_credentials = __commonJS({
|
|
2016
|
+
"../packages/tool-kit/out/credentials.js"(exports) {
|
|
2017
|
+
"use strict";
|
|
2018
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
2019
|
+
if (k2 === void 0) k2 = k;
|
|
2020
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
2021
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
2022
|
+
desc = { enumerable: true, get: function() {
|
|
2023
|
+
return m[k];
|
|
2024
|
+
} };
|
|
2025
|
+
}
|
|
2026
|
+
Object.defineProperty(o, k2, desc);
|
|
2027
|
+
} : function(o, m, k, k2) {
|
|
2028
|
+
if (k2 === void 0) k2 = k;
|
|
2029
|
+
o[k2] = m[k];
|
|
2030
|
+
});
|
|
2031
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
2032
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
2033
|
+
} : function(o, v) {
|
|
2034
|
+
o["default"] = v;
|
|
2035
|
+
});
|
|
2036
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
|
|
2037
|
+
var ownKeys = function(o) {
|
|
2038
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
2039
|
+
var ar = [];
|
|
2040
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
2041
|
+
return ar;
|
|
2042
|
+
};
|
|
2043
|
+
return ownKeys(o);
|
|
2044
|
+
};
|
|
2045
|
+
return function(mod) {
|
|
2046
|
+
if (mod && mod.__esModule) return mod;
|
|
2047
|
+
var result = {};
|
|
2048
|
+
if (mod != null) {
|
|
2049
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
2050
|
+
}
|
|
2051
|
+
__setModuleDefault(result, mod);
|
|
2052
|
+
return result;
|
|
2053
|
+
};
|
|
2054
|
+
}();
|
|
2055
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2056
|
+
exports.credentialsFilePath = credentialsFilePath;
|
|
2057
|
+
exports.readMachineCredentials = readMachineCredentials;
|
|
2058
|
+
exports.writeMachineCredentials = writeMachineCredentials;
|
|
2059
|
+
exports.writeTopLevelCredentials = writeTopLevelCredentials;
|
|
2060
|
+
exports.readHostCredentials = readHostCredentials;
|
|
2061
|
+
exports.writeHostCredentials = writeHostCredentials;
|
|
2062
|
+
exports.removeHostCredentials = removeHostCredentials;
|
|
2063
|
+
var fs = __importStar(__require("fs"));
|
|
2064
|
+
var path = __importStar(__require("path"));
|
|
2065
|
+
var tokenStore_1 = require_tokenStore();
|
|
2066
|
+
function credentialsFilePath() {
|
|
2067
|
+
return path.join((0, tokenStore_1.ascendaHome)(), "credentials.json");
|
|
2068
|
+
}
|
|
2069
|
+
function readMachineCredentials() {
|
|
2070
|
+
try {
|
|
2071
|
+
const raw = fs.readFileSync(credentialsFilePath(), "utf8").trim();
|
|
2072
|
+
if (!raw)
|
|
2073
|
+
return void 0;
|
|
2074
|
+
const parsed = JSON.parse(raw);
|
|
2075
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
2076
|
+
return void 0;
|
|
2077
|
+
return parsed;
|
|
2078
|
+
} catch {
|
|
2079
|
+
return void 0;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
function writeMachineCredentials(credentials) {
|
|
2083
|
+
const file = credentialsFilePath();
|
|
2084
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 448 });
|
|
2085
|
+
fs.writeFileSync(file, `${JSON.stringify(credentials, null, 2)}
|
|
2086
|
+
`, { encoding: "utf8", mode: 384 });
|
|
2087
|
+
if (process.platform !== "win32") {
|
|
2088
|
+
fs.chmodSync(path.dirname(file), 448);
|
|
2089
|
+
fs.chmodSync(file, 384);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
function writeTopLevelCredentials(credentials) {
|
|
2093
|
+
const existing = readMachineCredentials();
|
|
2094
|
+
writeMachineCredentials({ ...credentials, ...existing?.tools ? { tools: existing.tools } : {} });
|
|
2095
|
+
}
|
|
2096
|
+
function readHostCredentials(host) {
|
|
2097
|
+
const entry = readMachineCredentials()?.tools?.[host];
|
|
2098
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
2099
|
+
return void 0;
|
|
2100
|
+
return entry;
|
|
2101
|
+
}
|
|
2102
|
+
function writeHostCredentials(host, credentials) {
|
|
2103
|
+
const existing = readMachineCredentials() ?? {};
|
|
2104
|
+
writeMachineCredentials({ ...existing, tools: { ...existing.tools ?? {}, [host]: credentials } });
|
|
2105
|
+
}
|
|
2106
|
+
function removeHostCredentials(host) {
|
|
2107
|
+
const existing = readMachineCredentials();
|
|
2108
|
+
if (!existing?.tools || !(host in existing.tools))
|
|
2109
|
+
return;
|
|
2110
|
+
const tools = { ...existing.tools };
|
|
2111
|
+
delete tools[host];
|
|
2112
|
+
const next = { ...existing };
|
|
2113
|
+
if (Object.keys(tools).length)
|
|
2114
|
+
next.tools = tools;
|
|
2115
|
+
else
|
|
2116
|
+
delete next.tools;
|
|
2117
|
+
writeMachineCredentials(next);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
|
|
2122
|
+
// ../packages/tool-kit/out/forgeProject.js
|
|
2123
|
+
var require_forgeProject = __commonJS({
|
|
2124
|
+
"../packages/tool-kit/out/forgeProject.js"(exports) {
|
|
2125
|
+
"use strict";
|
|
2126
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
2127
|
+
if (k2 === void 0) k2 = k;
|
|
2128
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
2129
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
2130
|
+
desc = { enumerable: true, get: function() {
|
|
2131
|
+
return m[k];
|
|
2132
|
+
} };
|
|
2133
|
+
}
|
|
2134
|
+
Object.defineProperty(o, k2, desc);
|
|
2135
|
+
} : function(o, m, k, k2) {
|
|
2136
|
+
if (k2 === void 0) k2 = k;
|
|
2137
|
+
o[k2] = m[k];
|
|
2138
|
+
});
|
|
2139
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
2140
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
2141
|
+
} : function(o, v) {
|
|
2142
|
+
o["default"] = v;
|
|
2143
|
+
});
|
|
2144
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
|
|
2145
|
+
var ownKeys = function(o) {
|
|
2146
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
2147
|
+
var ar = [];
|
|
2148
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
2149
|
+
return ar;
|
|
2150
|
+
};
|
|
2151
|
+
return ownKeys(o);
|
|
2152
|
+
};
|
|
2153
|
+
return function(mod) {
|
|
2154
|
+
if (mod && mod.__esModule) return mod;
|
|
2155
|
+
var result = {};
|
|
2156
|
+
if (mod != null) {
|
|
2157
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
2158
|
+
}
|
|
2159
|
+
__setModuleDefault(result, mod);
|
|
2160
|
+
return result;
|
|
2161
|
+
};
|
|
2162
|
+
}();
|
|
2163
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2164
|
+
exports.forgeProjectHash = forgeProjectHash2;
|
|
2165
|
+
exports.parseForgeFullName = parseForgeFullName;
|
|
2166
|
+
exports.readForgeFullName = readForgeFullName;
|
|
2167
|
+
exports.forgeFullNameFromConfig = forgeFullNameFromConfig;
|
|
2168
|
+
exports.recordForgeProjectAlias = recordForgeProjectAlias;
|
|
2169
|
+
var fs = __importStar(__require("fs"));
|
|
2170
|
+
var path = __importStar(__require("path"));
|
|
2171
|
+
var contextRegistry_1 = require_contextRegistry();
|
|
2172
|
+
function forgeProjectHash2(value) {
|
|
2173
|
+
let h = 2166136261;
|
|
2174
|
+
for (let i = 0; i < value.length; i++) {
|
|
2175
|
+
h ^= value.charCodeAt(i);
|
|
2176
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
2177
|
+
}
|
|
2178
|
+
return h.toString(16).padStart(8, "0");
|
|
2179
|
+
}
|
|
2180
|
+
function parseForgeFullName(remoteUrl) {
|
|
2181
|
+
if (!remoteUrl)
|
|
2182
|
+
return null;
|
|
2183
|
+
const trimmed = remoteUrl.trim();
|
|
2184
|
+
if (!trimmed)
|
|
2185
|
+
return null;
|
|
2186
|
+
const scp = /^(?:[^@/]+@)?([^/:]+):(.+)$/.exec(trimmed);
|
|
2187
|
+
const scheme = /^([a-z][a-z0-9+.-]*):\/\/(?:[^@/]*@)?([^/:]+)(?::\d+)?\/(.+)$/i.exec(trimmed);
|
|
2188
|
+
let host;
|
|
2189
|
+
let repoPath;
|
|
2190
|
+
if (scheme) {
|
|
2191
|
+
host = scheme[2];
|
|
2192
|
+
repoPath = scheme[3];
|
|
2193
|
+
} else if (scp && !/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) {
|
|
2194
|
+
host = scp[1];
|
|
2195
|
+
repoPath = scp[2];
|
|
2196
|
+
} else {
|
|
2197
|
+
return null;
|
|
2198
|
+
}
|
|
2199
|
+
const normalizedHost = host.toLowerCase().replace(/^www\./, "");
|
|
2200
|
+
if (normalizedHost !== "github.com")
|
|
2201
|
+
return null;
|
|
2202
|
+
const segments = repoPath.split("/").filter((segment) => segment.length > 0);
|
|
2203
|
+
if (segments.length < 2)
|
|
2204
|
+
return null;
|
|
2205
|
+
const owner = segments[0];
|
|
2206
|
+
const repo = segments[1].replace(/\.git$/, "");
|
|
2207
|
+
if (!owner || !repo)
|
|
2208
|
+
return null;
|
|
2209
|
+
return `${owner}/${repo}`;
|
|
2210
|
+
}
|
|
2211
|
+
function readForgeFullName(repositoryRoot) {
|
|
2212
|
+
if (!repositoryRoot)
|
|
2213
|
+
return null;
|
|
2214
|
+
let config;
|
|
2215
|
+
try {
|
|
2216
|
+
config = fs.readFileSync(path.join(repositoryRoot, ".git", "config"), "utf8");
|
|
2217
|
+
} catch {
|
|
2218
|
+
return null;
|
|
2219
|
+
}
|
|
2220
|
+
return forgeFullNameFromConfig(config);
|
|
2221
|
+
}
|
|
2222
|
+
function forgeFullNameFromConfig(config) {
|
|
2223
|
+
const remotes = /* @__PURE__ */ new Map();
|
|
2224
|
+
let currentRemote = null;
|
|
2225
|
+
for (const rawLine of config.split(/\r?\n/)) {
|
|
2226
|
+
const line = rawLine.trim();
|
|
2227
|
+
if (!line || line.startsWith("#") || line.startsWith(";"))
|
|
2228
|
+
continue;
|
|
2229
|
+
const section = /^\[([^\]]*)\]$/.exec(line);
|
|
2230
|
+
if (section) {
|
|
2231
|
+
const remote = /^remote\s+"(.*)"$/.exec(section[1].trim());
|
|
2232
|
+
currentRemote = remote ? remote[1] : null;
|
|
2233
|
+
continue;
|
|
2234
|
+
}
|
|
2235
|
+
if (!currentRemote)
|
|
2236
|
+
continue;
|
|
2237
|
+
const entry = /^url\s*=\s*(.*)$/.exec(line);
|
|
2238
|
+
if (entry && !remotes.has(currentRemote))
|
|
2239
|
+
remotes.set(currentRemote, entry[1].trim());
|
|
2240
|
+
}
|
|
2241
|
+
const ordered = [
|
|
2242
|
+
...remotes.has("origin") ? ["origin"] : [],
|
|
2243
|
+
...remotes.has("upstream") ? ["upstream"] : [],
|
|
2244
|
+
...[...remotes.keys()].filter((name) => name !== "origin" && name !== "upstream")
|
|
2245
|
+
];
|
|
2246
|
+
for (const name of ordered) {
|
|
2247
|
+
const fullName = parseForgeFullName(remotes.get(name));
|
|
2248
|
+
if (fullName)
|
|
2249
|
+
return fullName;
|
|
2250
|
+
}
|
|
2251
|
+
return null;
|
|
2252
|
+
}
|
|
2253
|
+
function recordForgeProjectAlias(context, options) {
|
|
2254
|
+
try {
|
|
2255
|
+
if (!context?.projectHash || !context.projectLabel || !context.projectPath)
|
|
2256
|
+
return false;
|
|
2257
|
+
const fullName = readForgeFullName(context.projectPath);
|
|
2258
|
+
if (!fullName)
|
|
2259
|
+
return false;
|
|
2260
|
+
const variants = [fullName, fullName.toLowerCase()].filter((value, index, all) => all.indexOf(value) === index);
|
|
2261
|
+
let wrote = false;
|
|
2262
|
+
for (const variant of variants) {
|
|
2263
|
+
const hash = forgeProjectHash2(variant);
|
|
2264
|
+
if (hash === context.projectHash || hash === context.workspaceHash)
|
|
1299
2265
|
continue;
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
existing.kind = update.kind;
|
|
1303
|
-
dirty = true;
|
|
1304
|
-
}
|
|
1305
|
-
if (existing.label !== update.label && update.kind !== "alias") {
|
|
1306
|
-
existing.label = update.label;
|
|
1307
|
-
dirty = true;
|
|
1308
|
-
}
|
|
1309
|
-
if (update.observedPath && !existing.paths.includes(update.observedPath)) {
|
|
1310
|
-
if (existing.paths.length < MAX_PATHS_PER_ENTRY)
|
|
1311
|
-
existing.paths.push(update.observedPath);
|
|
1312
|
-
dirty = true;
|
|
1313
|
-
}
|
|
1314
|
-
if (dayOf(existing.lastSeenAt) !== dayOf(nowIso)) {
|
|
1315
|
-
existing.lastSeenAt = nowIso;
|
|
1316
|
-
dirty = true;
|
|
1317
|
-
}
|
|
2266
|
+
if ((0, contextRegistry_1.recordWorkContextAlias)(hash, context.projectLabel, context.projectPath, options))
|
|
2267
|
+
wrote = true;
|
|
1318
2268
|
}
|
|
1319
|
-
|
|
1320
|
-
return false;
|
|
1321
|
-
writeRegistry(registryFilePath, registry);
|
|
1322
|
-
return true;
|
|
2269
|
+
return wrote;
|
|
1323
2270
|
} catch {
|
|
1324
2271
|
return false;
|
|
1325
2272
|
}
|
|
1326
2273
|
}
|
|
1327
|
-
function dayOf(iso) {
|
|
1328
|
-
return iso.slice(0, 10);
|
|
1329
|
-
}
|
|
1330
|
-
function writeRegistry(registryFilePath, registry) {
|
|
1331
|
-
const dir = path.dirname(registryFilePath);
|
|
1332
|
-
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
1333
|
-
const tmp = `${registryFilePath}.${process.pid}.tmp`;
|
|
1334
|
-
fs.writeFileSync(tmp, `${JSON.stringify(registry, null, 2)}
|
|
1335
|
-
`, { encoding: "utf8", mode: 384 });
|
|
1336
|
-
fs.renameSync(tmp, registryFilePath);
|
|
1337
|
-
if (process.platform !== "win32") {
|
|
1338
|
-
fs.chmodSync(registryFilePath, 384);
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
2274
|
}
|
|
1342
2275
|
});
|
|
1343
2276
|
|
|
@@ -1467,6 +2400,10 @@ var require_workContext = __commonJS({
|
|
|
1467
2400
|
}();
|
|
1468
2401
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1469
2402
|
exports.deriveWorkContext = deriveWorkContext;
|
|
2403
|
+
exports.normalizeBranchName = normalizeBranchName;
|
|
2404
|
+
exports.deriveBranchHash = deriveBranchHash;
|
|
2405
|
+
exports.readBranchName = readBranchName;
|
|
2406
|
+
exports.deriveBranchHashForCwd = deriveBranchHashForCwd;
|
|
1470
2407
|
var fs = __importStar(__require("fs"));
|
|
1471
2408
|
var path = __importStar(__require("path"));
|
|
1472
2409
|
var salt_1 = require_salt();
|
|
@@ -1481,6 +2418,8 @@ var require_workContext = __commonJS({
|
|
|
1481
2418
|
} catch {
|
|
1482
2419
|
roots = null;
|
|
1483
2420
|
}
|
|
2421
|
+
if (!roots)
|
|
2422
|
+
roots = inferRootsFromPath(startPath);
|
|
1484
2423
|
const workspacePath = roots?.checkoutRoot ?? startPath;
|
|
1485
2424
|
const workspaceLabel = basenameOf(workspacePath);
|
|
1486
2425
|
if (!workspaceLabel)
|
|
@@ -1509,9 +2448,12 @@ var require_workContext = __commonJS({
|
|
|
1509
2448
|
stat = null;
|
|
1510
2449
|
}
|
|
1511
2450
|
if (stat?.isDirectory())
|
|
1512
|
-
return { checkoutRoot: dir, canonicalRoot: dir };
|
|
1513
|
-
if (stat?.isFile())
|
|
1514
|
-
|
|
2451
|
+
return { checkoutRoot: dir, canonicalRoot: dir, gitDir: dotGit };
|
|
2452
|
+
if (stat?.isFile()) {
|
|
2453
|
+
const gitDir = readGitdirPointer(dotGit, dir);
|
|
2454
|
+
const canonicalRoot = (gitDir ? worktreeParentRoot(gitDir) : null) ?? dir;
|
|
2455
|
+
return { checkoutRoot: dir, canonicalRoot, gitDir };
|
|
2456
|
+
}
|
|
1515
2457
|
const parent = path.dirname(dir);
|
|
1516
2458
|
if (parent === dir)
|
|
1517
2459
|
return null;
|
|
@@ -1519,22 +2461,45 @@ var require_workContext = __commonJS({
|
|
|
1519
2461
|
}
|
|
1520
2462
|
return null;
|
|
1521
2463
|
}
|
|
1522
|
-
function
|
|
1523
|
-
let gitdir;
|
|
2464
|
+
function readGitdirPointer(dotGitFile, containingDir) {
|
|
1524
2465
|
try {
|
|
1525
2466
|
const match = /^gitdir:\s*(.+)\s*$/m.exec(fs.readFileSync(dotGitFile, "utf8"));
|
|
1526
2467
|
if (!match)
|
|
1527
2468
|
return null;
|
|
1528
|
-
|
|
2469
|
+
return path.resolve(containingDir, match[1].trim());
|
|
1529
2470
|
} catch {
|
|
1530
2471
|
return null;
|
|
1531
2472
|
}
|
|
1532
|
-
|
|
2473
|
+
}
|
|
2474
|
+
function worktreeParentRoot(resolvedGitDir) {
|
|
1533
2475
|
const marker = `${path.sep}.git${path.sep}worktrees${path.sep}`;
|
|
1534
|
-
const idx =
|
|
2476
|
+
const idx = resolvedGitDir.indexOf(marker);
|
|
1535
2477
|
if (idx === -1)
|
|
1536
2478
|
return null;
|
|
1537
|
-
return
|
|
2479
|
+
return resolvedGitDir.slice(0, idx);
|
|
2480
|
+
}
|
|
2481
|
+
function inferRootsFromPath(startPath) {
|
|
2482
|
+
const sep = startPath.includes("\\") && !startPath.includes("/") ? "\\" : "/";
|
|
2483
|
+
const leading = /^[\\/]/.test(startPath) ? sep : "";
|
|
2484
|
+
const segments = startPath.split(/[\\/]/).filter(Boolean);
|
|
2485
|
+
const join = (count) => leading + segments.slice(0, count).join(sep);
|
|
2486
|
+
for (let i = 0; i + 2 < segments.length; i++) {
|
|
2487
|
+
if (segments[i] === ".claude" && segments[i + 1] === "worktrees") {
|
|
2488
|
+
if (i === 0)
|
|
2489
|
+
return null;
|
|
2490
|
+
return { checkoutRoot: join(i + 3), canonicalRoot: join(i), gitDir: null };
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
for (let i = 0; i + 1 < segments.length; i++) {
|
|
2494
|
+
const folder = segments[i];
|
|
2495
|
+
const suffix = ["-worktrees", "-wt"].find((s) => folder.endsWith(s) && folder.length > s.length);
|
|
2496
|
+
if (!suffix)
|
|
2497
|
+
continue;
|
|
2498
|
+
const repoName = folder.slice(0, -suffix.length);
|
|
2499
|
+
const canonicalRoot = leading + [...segments.slice(0, i), repoName].join(sep);
|
|
2500
|
+
return { checkoutRoot: join(i + 2), canonicalRoot, gitDir: null };
|
|
2501
|
+
}
|
|
2502
|
+
return null;
|
|
1538
2503
|
}
|
|
1539
2504
|
function stripTrailingSeparators(value) {
|
|
1540
2505
|
let end = value.length;
|
|
@@ -1546,6 +2511,55 @@ var require_workContext = __commonJS({
|
|
|
1546
2511
|
const segment = value.split(/[\\/]/).filter(Boolean).pop() ?? null;
|
|
1547
2512
|
return segment && segment.length > 0 ? segment : null;
|
|
1548
2513
|
}
|
|
2514
|
+
var REFS_HEADS_PREFIX = "refs/heads/";
|
|
2515
|
+
function normalizeBranchName(branch) {
|
|
2516
|
+
if (!branch)
|
|
2517
|
+
return null;
|
|
2518
|
+
let name = branch.trim();
|
|
2519
|
+
if (name.startsWith(REFS_HEADS_PREFIX))
|
|
2520
|
+
name = name.slice(REFS_HEADS_PREFIX.length).trim();
|
|
2521
|
+
if (!name || name === "HEAD")
|
|
2522
|
+
return null;
|
|
2523
|
+
return name;
|
|
2524
|
+
}
|
|
2525
|
+
function deriveBranchHash(branch, saltFilePath) {
|
|
2526
|
+
const name = normalizeBranchName(branch);
|
|
2527
|
+
if (!name)
|
|
2528
|
+
return null;
|
|
2529
|
+
try {
|
|
2530
|
+
return (0, salt_1.hashWithMachineSalt)(name, saltFilePath);
|
|
2531
|
+
} catch {
|
|
2532
|
+
return null;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
function readBranchName(cwd) {
|
|
2536
|
+
if (!cwd || !cwd.trim())
|
|
2537
|
+
return null;
|
|
2538
|
+
let gitDir = null;
|
|
2539
|
+
try {
|
|
2540
|
+
gitDir = resolveRepositoryRoots(stripTrailingSeparators(cwd.trim()))?.gitDir ?? null;
|
|
2541
|
+
} catch {
|
|
2542
|
+
gitDir = null;
|
|
2543
|
+
}
|
|
2544
|
+
if (!gitDir)
|
|
2545
|
+
return null;
|
|
2546
|
+
let head;
|
|
2547
|
+
try {
|
|
2548
|
+
head = fs.readFileSync(path.join(gitDir, "HEAD"), "utf8").trim();
|
|
2549
|
+
} catch {
|
|
2550
|
+
return null;
|
|
2551
|
+
}
|
|
2552
|
+
const match = /^ref:\s*(.+)$/.exec(head);
|
|
2553
|
+
if (!match)
|
|
2554
|
+
return null;
|
|
2555
|
+
const ref = match[1].trim();
|
|
2556
|
+
if (!ref.startsWith(REFS_HEADS_PREFIX))
|
|
2557
|
+
return null;
|
|
2558
|
+
return normalizeBranchName(ref);
|
|
2559
|
+
}
|
|
2560
|
+
function deriveBranchHashForCwd(cwd, saltFilePath) {
|
|
2561
|
+
return deriveBranchHash(readBranchName(cwd), saltFilePath);
|
|
2562
|
+
}
|
|
1549
2563
|
}
|
|
1550
2564
|
});
|
|
1551
2565
|
|
|
@@ -1554,35 +2568,69 @@ var require_hookAdapter = __commonJS({
|
|
|
1554
2568
|
"../packages/tool-kit/out/hookAdapter.js"(exports) {
|
|
1555
2569
|
"use strict";
|
|
1556
2570
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1557
|
-
exports.DEFAULT_API_BASE_URL = void 0;
|
|
2571
|
+
exports.MissingInstallationIdError = exports.DEFAULT_API_BASE_URL = void 0;
|
|
2572
|
+
exports.resolveCliAgentInstallationId = resolveCliAgentInstallationId;
|
|
1558
2573
|
exports.resolveContextHashes = resolveContextHashes;
|
|
1559
2574
|
exports.loadCliAgentConfig = loadCliAgentConfig;
|
|
1560
2575
|
exports.deliverHookEvents = deliverHookEvents;
|
|
1561
2576
|
var contextRegistry_1 = require_contextRegistry();
|
|
2577
|
+
var credentials_1 = require_credentials();
|
|
2578
|
+
var forgeProject_1 = require_forgeProject();
|
|
1562
2579
|
var eventLog_1 = require_eventLog();
|
|
1563
2580
|
var eventSender_1 = require_eventSender();
|
|
2581
|
+
var stateStore_1 = require_stateStore();
|
|
1564
2582
|
var tokenStore_1 = require_tokenStore();
|
|
1565
2583
|
var workContext_1 = require_workContext();
|
|
1566
2584
|
exports.DEFAULT_API_BASE_URL = "https://api.ascenda.one";
|
|
2585
|
+
var MissingInstallationIdError = class extends Error {
|
|
2586
|
+
/** The token files that were considered — none, or too many to pick from. */
|
|
2587
|
+
candidates;
|
|
2588
|
+
toolType;
|
|
2589
|
+
constructor(toolType, candidates, setupCommand) {
|
|
2590
|
+
super(candidates.length === 0 ? `Not configured: no ASCENDA_TOOL_INSTALLATION_ID, no pairing in ~/.ascenda/credentials.json, and no ${toolType} token in ~/.ascenda/tokens/. Run: ${setupCommand}` : `Not configured: no ASCENDA_TOOL_INSTALLATION_ID, no pairing in ~/.ascenda/credentials.json, and ${candidates.length} ${toolType} tokens in ~/.ascenda/tokens/ (${candidates.join(", ")}) \u2014 refusing to guess. Export ASCENDA_TOOL_INSTALLATION_ID to choose one, or run: ${setupCommand}`);
|
|
2591
|
+
this.name = "MissingInstallationIdError";
|
|
2592
|
+
this.toolType = toolType;
|
|
2593
|
+
this.candidates = candidates;
|
|
2594
|
+
}
|
|
2595
|
+
};
|
|
2596
|
+
exports.MissingInstallationIdError = MissingInstallationIdError;
|
|
2597
|
+
function resolveCliAgentInstallationId(toolType, identity = {}) {
|
|
2598
|
+
const fromEnv = process.env.ASCENDA_TOOL_INSTALLATION_ID?.trim();
|
|
2599
|
+
if (fromEnv)
|
|
2600
|
+
return { toolInstallationId: qualify(toolType, fromEnv), source: "env" };
|
|
2601
|
+
const fromCredentials = identity.host ? (0, credentials_1.readHostCredentials)(identity.host)?.toolInstallationId?.trim() : void 0;
|
|
2602
|
+
if (fromCredentials)
|
|
2603
|
+
return { toolInstallationId: qualify(toolType, fromCredentials), source: "credentials" };
|
|
2604
|
+
const candidates = (0, tokenStore_1.listPersistedToolInstallationIds)(toolType);
|
|
2605
|
+
if (candidates.length === 1)
|
|
2606
|
+
return { toolInstallationId: candidates[0], source: "disk" };
|
|
2607
|
+
throw new MissingInstallationIdError(toolType, candidates, identity.setupCommand ?? defaultSetupCommand(identity.host));
|
|
2608
|
+
}
|
|
2609
|
+
function defaultSetupCommand(host) {
|
|
2610
|
+
return host ? `npx @ascenda-one/${host.replace(/_cli$/, "")}-hooks setup` : "the agent's setup command";
|
|
2611
|
+
}
|
|
2612
|
+
function qualify(toolType, value) {
|
|
2613
|
+
return value.includes(":") ? value : `${toolType}:${value}`;
|
|
2614
|
+
}
|
|
1567
2615
|
function resolveContextHashes(cwd) {
|
|
1568
2616
|
const workspaceOverride = process.env.ASCENDA_WORKSPACE_HASH?.trim() || null;
|
|
1569
2617
|
const projectOverride = process.env.ASCENDA_PROJECT_HASH?.trim() || null;
|
|
1570
2618
|
if (workspaceOverride && projectOverride)
|
|
1571
2619
|
return { workspaceHash: workspaceOverride, projectHash: projectOverride };
|
|
1572
2620
|
const context = (0, workContext_1.deriveWorkContext)(cwd ?? process.cwd());
|
|
1573
|
-
if (context)
|
|
2621
|
+
if (context) {
|
|
1574
2622
|
(0, contextRegistry_1.recordWorkContext)(context);
|
|
2623
|
+
(0, forgeProject_1.recordForgeProjectAlias)(context);
|
|
2624
|
+
}
|
|
1575
2625
|
return {
|
|
1576
2626
|
workspaceHash: workspaceOverride ?? context?.workspaceHash ?? null,
|
|
1577
2627
|
projectHash: projectOverride ?? context?.projectHash ?? null
|
|
1578
2628
|
};
|
|
1579
2629
|
}
|
|
1580
|
-
function loadCliAgentConfig(toolType, sessionIdFromHook, cwd) {
|
|
1581
|
-
const
|
|
1582
|
-
const
|
|
1583
|
-
|
|
1584
|
-
throw new Error("Missing ASCENDA_TOOL_INSTALLATION_ID");
|
|
1585
|
-
const toolInstallationId = toolInstallationIdRaw.trim().includes(":") ? toolInstallationIdRaw.trim() : `${toolType}:${toolInstallationIdRaw.trim()}`;
|
|
2630
|
+
function loadCliAgentConfig(toolType, sessionIdFromHook, cwd, identity = {}) {
|
|
2631
|
+
const credentials = identity.host ? (0, credentials_1.readHostCredentials)(identity.host) : void 0;
|
|
2632
|
+
const apiBaseUrl = (process.env.ASCENDA_API_BASE_URL ?? credentials?.apiBaseUrl ?? exports.DEFAULT_API_BASE_URL).replace(/\/$/, "");
|
|
2633
|
+
const { toolInstallationId } = resolveCliAgentInstallationId(toolType, identity);
|
|
1586
2634
|
const tokenFilePath = process.env.ASCENDA_EVENT_WRITE_TOKEN_FILE ?? (0, tokenStore_1.defaultTokenFilePath)(toolInstallationId);
|
|
1587
2635
|
const fileToken = (0, tokenStore_1.readTokenFile)(tokenFilePath);
|
|
1588
2636
|
const eventWriteToken = fileToken ?? process.env.ASCENDA_EVENT_WRITE_TOKEN;
|
|
@@ -1596,7 +2644,10 @@ var require_hookAdapter = __commonJS({
|
|
|
1596
2644
|
toolInstallationId,
|
|
1597
2645
|
eventWriteToken,
|
|
1598
2646
|
tokenFilePath,
|
|
1599
|
-
|
|
2647
|
+
// An empty ASCENDA_SESSION_ID is "unset", not "override with nothing":
|
|
2648
|
+
// read raw, `ASCENDA_SESSION_ID=""` beat a real hook session and shipped
|
|
2649
|
+
// an empty string, grouping unrelated rows under a value naming no session.
|
|
2650
|
+
sessionId: process.env.ASCENDA_SESSION_ID?.trim() || sessionIdFromHook || null,
|
|
1600
2651
|
workspaceHash: contextHashes.workspaceHash,
|
|
1601
2652
|
projectHash: contextHashes.projectHash,
|
|
1602
2653
|
// Agents await command hooks; fail fast rather than stall the user's turn.
|
|
@@ -1609,8 +2660,10 @@ var require_hookAdapter = __commonJS({
|
|
|
1609
2660
|
const notice = options.onNotice ?? ((message) => console.error(message));
|
|
1610
2661
|
let config;
|
|
1611
2662
|
try {
|
|
1612
|
-
config = loadCliAgentConfig(options.toolType, options.sessionId, options.cwd);
|
|
2663
|
+
config = loadCliAgentConfig(options.toolType, options.sessionId, options.cwd, options);
|
|
1613
2664
|
} catch (error) {
|
|
2665
|
+
if (error instanceof MissingInstallationIdError)
|
|
2666
|
+
journalSkippedSend(options.host, error);
|
|
1614
2667
|
const logFile = (0, eventLog_1.resolveEventLogPath)();
|
|
1615
2668
|
if (!logFile)
|
|
1616
2669
|
throw error;
|
|
@@ -1650,13 +2703,19 @@ var require_hookAdapter = __commonJS({
|
|
|
1650
2703
|
} else if (result === "auth_failed") {
|
|
1651
2704
|
notice("Ascenda telemetry paused: connection revoked or expired. Re-pair via an Ascenda IDE extension or pairing-sim.");
|
|
1652
2705
|
} else if (result === "transport_error") {
|
|
1653
|
-
notice("Ascenda telemetry paused: the ingest endpoint could not be reached. Your work is unaffected.");
|
|
2706
|
+
notice("Ascenda telemetry paused: the ingest endpoint could not be reached; the event is kept in the outbox. Your work is unaffected.");
|
|
1654
2707
|
} else {
|
|
1655
2708
|
notice(`Ascenda telemetry rejected: ${result}`);
|
|
1656
2709
|
}
|
|
1657
2710
|
return;
|
|
1658
2711
|
}
|
|
1659
2712
|
}
|
|
2713
|
+
function journalSkippedSend(host, error) {
|
|
2714
|
+
const who = host ? `${host}: ` : "";
|
|
2715
|
+
(0, stateStore_1.recordSendOutcome)((0, stateStore_1.unresolvedStateFilePath)(error.toolType), (0, stateStore_1.unresolvedToolInstallationId)(error.toolType), "skipped_no_installation_id", {
|
|
2716
|
+
detail: error.candidates.length === 0 ? `${who}no ASCENDA_TOOL_INSTALLATION_ID, no credentials.json pairing, no ${error.toolType} token file` : `${who}no ASCENDA_TOOL_INSTALLATION_ID, no credentials.json pairing, ${error.candidates.length} ${error.toolType} token files (${error.candidates.join(", ")})`
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
1660
2719
|
function parsePositiveInt(value) {
|
|
1661
2720
|
const n = Number(value);
|
|
1662
2721
|
return Number.isInteger(n) && n > 0 ? n : void 0;
|
|
@@ -1664,6 +2723,387 @@ var require_hookAdapter = __commonJS({
|
|
|
1664
2723
|
}
|
|
1665
2724
|
});
|
|
1666
2725
|
|
|
2726
|
+
// ../packages/tool-kit/out/cliAgentSetup.js
|
|
2727
|
+
var require_cliAgentSetup = __commonJS({
|
|
2728
|
+
"../packages/tool-kit/out/cliAgentSetup.js"(exports) {
|
|
2729
|
+
"use strict";
|
|
2730
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
2731
|
+
if (k2 === void 0) k2 = k;
|
|
2732
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
2733
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
2734
|
+
desc = { enumerable: true, get: function() {
|
|
2735
|
+
return m[k];
|
|
2736
|
+
} };
|
|
2737
|
+
}
|
|
2738
|
+
Object.defineProperty(o, k2, desc);
|
|
2739
|
+
} : function(o, m, k, k2) {
|
|
2740
|
+
if (k2 === void 0) k2 = k;
|
|
2741
|
+
o[k2] = m[k];
|
|
2742
|
+
});
|
|
2743
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
2744
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
2745
|
+
} : function(o, v) {
|
|
2746
|
+
o["default"] = v;
|
|
2747
|
+
});
|
|
2748
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
|
|
2749
|
+
var ownKeys = function(o) {
|
|
2750
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
2751
|
+
var ar = [];
|
|
2752
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
2753
|
+
return ar;
|
|
2754
|
+
};
|
|
2755
|
+
return ownKeys(o);
|
|
2756
|
+
};
|
|
2757
|
+
return function(mod) {
|
|
2758
|
+
if (mod && mod.__esModule) return mod;
|
|
2759
|
+
var result = {};
|
|
2760
|
+
if (mod != null) {
|
|
2761
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
2762
|
+
}
|
|
2763
|
+
__setModuleDefault(result, mod);
|
|
2764
|
+
return result;
|
|
2765
|
+
};
|
|
2766
|
+
}();
|
|
2767
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2768
|
+
exports.isCliAgentManagementCommand = isCliAgentManagementCommand;
|
|
2769
|
+
exports.cliAgentHookBinPath = cliAgentHookBinPath;
|
|
2770
|
+
exports.runCliAgentSetup = runCliAgentSetup;
|
|
2771
|
+
exports.writeHookSettings = writeHookSettings;
|
|
2772
|
+
exports.findStaleHookCommands = findStaleHookCommands;
|
|
2773
|
+
var crypto = __importStar(__require("crypto"));
|
|
2774
|
+
var fs = __importStar(__require("fs"));
|
|
2775
|
+
var os = __importStar(__require("os"));
|
|
2776
|
+
var path = __importStar(__require("path"));
|
|
2777
|
+
var credentials_1 = require_credentials();
|
|
2778
|
+
var hookAdapter_1 = require_hookAdapter();
|
|
2779
|
+
var http_1 = require_http();
|
|
2780
|
+
var tokenStore_1 = require_tokenStore();
|
|
2781
|
+
var MANAGEMENT_COMMANDS = /* @__PURE__ */ new Set(["setup", "install", "status", "uninstall", "-h", "--help"]);
|
|
2782
|
+
function isCliAgentManagementCommand(argument) {
|
|
2783
|
+
return argument !== void 0 && MANAGEMENT_COMMANDS.has(argument);
|
|
2784
|
+
}
|
|
2785
|
+
function cliAgentHookBinPath(binaryName) {
|
|
2786
|
+
return path.join((0, tokenStore_1.ascendaHome)(), "bin", binaryName);
|
|
2787
|
+
}
|
|
2788
|
+
function usage(spec) {
|
|
2789
|
+
return `${spec.binaryName} setup \u2014 wire ${spec.displayName} to Ascenda telemetry
|
|
2790
|
+
|
|
2791
|
+
npx ${spec.packageName} setup [options]
|
|
2792
|
+
npx ${spec.packageName} status
|
|
2793
|
+
npx ${spec.packageName} uninstall
|
|
2794
|
+
|
|
2795
|
+
Options
|
|
2796
|
+
--api-base-url <url> ingest host (default ${hookAdapter_1.DEFAULT_API_BASE_URL})
|
|
2797
|
+
--local [port] shorthand for the local dev server (default port 4477)
|
|
2798
|
+
--tool-installation-id <id> reuse an existing pairing instead of creating one
|
|
2799
|
+
--token <eventWriteToken> reuse an existing token (stored 0600, never printed)
|
|
2800
|
+
--scope project|user where hooks are registered (default project)
|
|
2801
|
+
--project-dir <path> project root for --scope project (default cwd)
|
|
2802
|
+
--dry-run print what would change, write nothing
|
|
2803
|
+
-h, --help
|
|
2804
|
+
`;
|
|
2805
|
+
}
|
|
2806
|
+
async function runCliAgentSetup(argv, spec) {
|
|
2807
|
+
let options;
|
|
2808
|
+
try {
|
|
2809
|
+
options = parseArgs(argv, spec);
|
|
2810
|
+
} catch (error) {
|
|
2811
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
2812
|
+
return 1;
|
|
2813
|
+
}
|
|
2814
|
+
if (options.action === "help") {
|
|
2815
|
+
console.log(usage(spec));
|
|
2816
|
+
return 0;
|
|
2817
|
+
}
|
|
2818
|
+
if (options.action === "status")
|
|
2819
|
+
return printStatus(options, spec);
|
|
2820
|
+
if (options.action === "uninstall")
|
|
2821
|
+
return uninstall(options, spec);
|
|
2822
|
+
const apiBaseUrl = (options.apiBaseUrl ?? (0, credentials_1.readHostCredentials)(spec.host)?.apiBaseUrl ?? hookAdapter_1.DEFAULT_API_BASE_URL).replace(/\/$/, "");
|
|
2823
|
+
console.log(`Ascenda setup for ${spec.displayName} \u2014 ${apiBaseUrl}`);
|
|
2824
|
+
const identity = await resolveIdentity(apiBaseUrl, options, spec);
|
|
2825
|
+
if (!identity)
|
|
2826
|
+
return 1;
|
|
2827
|
+
console.log(` pairing ${identity.toolInstallationId}${identity.paired ? " (new)" : " (existing)"}`);
|
|
2828
|
+
const binary = installBinary(spec, options.dryRun);
|
|
2829
|
+
console.log(` hook binary ${binary}`);
|
|
2830
|
+
if (!options.dryRun) {
|
|
2831
|
+
(0, credentials_1.writeHostCredentials)(spec.host, { apiBaseUrl, toolInstallationId: identity.toolInstallationId, pairedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2832
|
+
}
|
|
2833
|
+
console.log(` credentials ${(0, credentials_1.credentialsFilePath)()} (tools.${spec.host})`);
|
|
2834
|
+
const settingsFile = spec.settings.settingsPath(options.scope, options.projectDir);
|
|
2835
|
+
const written = writeHookSettings(settingsFile, binary, spec, options.dryRun);
|
|
2836
|
+
if (written === null)
|
|
2837
|
+
return 1;
|
|
2838
|
+
console.log(` hooks ${settingsFile} (${spec.hookEvents.length} events${written ? "" : ", already current"})`);
|
|
2839
|
+
if (options.dryRun) {
|
|
2840
|
+
console.log("\nDry run \u2014 nothing was written.");
|
|
2841
|
+
return 0;
|
|
2842
|
+
}
|
|
2843
|
+
console.log(`
|
|
2844
|
+
Done. ${spec.restartHint}`);
|
|
2845
|
+
console.log(`Check anytime: npx ${spec.packageName} status`);
|
|
2846
|
+
return 0;
|
|
2847
|
+
}
|
|
2848
|
+
function parseArgs(argv, spec) {
|
|
2849
|
+
const options = {
|
|
2850
|
+
scope: "project",
|
|
2851
|
+
projectDir: process.cwd(),
|
|
2852
|
+
dryRun: false,
|
|
2853
|
+
action: "install"
|
|
2854
|
+
};
|
|
2855
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2856
|
+
const arg = argv[i];
|
|
2857
|
+
const next = () => {
|
|
2858
|
+
const value = argv[++i];
|
|
2859
|
+
if (value === void 0)
|
|
2860
|
+
throw new Error(`${arg} needs a value`);
|
|
2861
|
+
return value;
|
|
2862
|
+
};
|
|
2863
|
+
switch (arg) {
|
|
2864
|
+
case "setup":
|
|
2865
|
+
case "install":
|
|
2866
|
+
options.action = "install";
|
|
2867
|
+
break;
|
|
2868
|
+
case "status":
|
|
2869
|
+
options.action = "status";
|
|
2870
|
+
break;
|
|
2871
|
+
case "uninstall":
|
|
2872
|
+
options.action = "uninstall";
|
|
2873
|
+
break;
|
|
2874
|
+
case "--api-base-url":
|
|
2875
|
+
options.apiBaseUrl = next();
|
|
2876
|
+
break;
|
|
2877
|
+
case "--local": {
|
|
2878
|
+
const peek = argv[i + 1];
|
|
2879
|
+
const port = peek && /^\d+$/.test(peek) ? argv[++i] : "4477";
|
|
2880
|
+
options.apiBaseUrl = `http://localhost:${port}`;
|
|
2881
|
+
break;
|
|
2882
|
+
}
|
|
2883
|
+
case "--tool-installation-id":
|
|
2884
|
+
options.toolInstallationId = next();
|
|
2885
|
+
break;
|
|
2886
|
+
case "--token":
|
|
2887
|
+
options.token = next();
|
|
2888
|
+
break;
|
|
2889
|
+
case "--scope": {
|
|
2890
|
+
const value = next();
|
|
2891
|
+
if (value !== "project" && value !== "user")
|
|
2892
|
+
throw new Error(`--scope must be project or user, got ${value}`);
|
|
2893
|
+
options.scope = value;
|
|
2894
|
+
break;
|
|
2895
|
+
}
|
|
2896
|
+
case "--project-dir":
|
|
2897
|
+
options.projectDir = path.resolve(next());
|
|
2898
|
+
break;
|
|
2899
|
+
case "--dry-run":
|
|
2900
|
+
options.dryRun = true;
|
|
2901
|
+
break;
|
|
2902
|
+
case "-h":
|
|
2903
|
+
case "--help":
|
|
2904
|
+
options.action = "help";
|
|
2905
|
+
break;
|
|
2906
|
+
default:
|
|
2907
|
+
throw new Error(`unknown argument: ${arg}
|
|
2908
|
+
|
|
2909
|
+
${usage(spec)}`);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
return options;
|
|
2913
|
+
}
|
|
2914
|
+
async function resolveIdentity(apiBaseUrl, options, spec) {
|
|
2915
|
+
const existingId = options.toolInstallationId ?? (0, credentials_1.readHostCredentials)(spec.host)?.toolInstallationId;
|
|
2916
|
+
if (existingId && options.token) {
|
|
2917
|
+
if (!options.dryRun)
|
|
2918
|
+
(0, tokenStore_1.persistEventWriteToken)((0, tokenStore_1.defaultTokenFilePath)(existingId), options.token);
|
|
2919
|
+
return { toolInstallationId: existingId, paired: false };
|
|
2920
|
+
}
|
|
2921
|
+
if (existingId && (0, tokenStore_1.readTokenFile)((0, tokenStore_1.defaultTokenFilePath)(existingId))) {
|
|
2922
|
+
return { toolInstallationId: existingId, paired: false };
|
|
2923
|
+
}
|
|
2924
|
+
if (options.dryRun) {
|
|
2925
|
+
return { toolInstallationId: existingId ?? `${spec.toolType}:<paired at run time>`, paired: false };
|
|
2926
|
+
}
|
|
2927
|
+
const toolInstallationId = existingId ?? `${spec.toolType}:${crypto.randomUUID()}`;
|
|
2928
|
+
let session;
|
|
2929
|
+
try {
|
|
2930
|
+
session = await (0, http_1.createPairingSession)(apiBaseUrl, toolInstallationId, spec.toolType, `${spec.displayName} on ${os.hostname()}`);
|
|
2931
|
+
} catch (error) {
|
|
2932
|
+
console.error(`
|
|
2933
|
+
Could not reach ${apiBaseUrl} to pair: ${error instanceof Error ? error.message : String(error)}`);
|
|
2934
|
+
console.error("Start the local dev server and use --local, or pass --api-base-url for your backend.");
|
|
2935
|
+
return void 0;
|
|
2936
|
+
}
|
|
2937
|
+
const token = await pollForToken(apiBaseUrl, session.pairingSessionId, session.code, session.expiresAt);
|
|
2938
|
+
if (!token)
|
|
2939
|
+
return void 0;
|
|
2940
|
+
(0, tokenStore_1.persistEventWriteToken)((0, tokenStore_1.defaultTokenFilePath)(toolInstallationId), token);
|
|
2941
|
+
return { toolInstallationId, paired: true };
|
|
2942
|
+
}
|
|
2943
|
+
async function pollForToken(apiBaseUrl, pairingSessionId, code, expiresAt) {
|
|
2944
|
+
const deadline = Math.min(Date.parse(expiresAt) || Date.now() + 3e5, Date.now() + 3e5);
|
|
2945
|
+
let announced = false;
|
|
2946
|
+
while (Date.now() < deadline) {
|
|
2947
|
+
const status = await (0, http_1.getPairingStatus)(apiBaseUrl, pairingSessionId);
|
|
2948
|
+
if (status.status === "paired" && status.eventWriteToken)
|
|
2949
|
+
return status.eventWriteToken;
|
|
2950
|
+
if (status.status === "expired" || status.status === "cancelled") {
|
|
2951
|
+
console.error(`
|
|
2952
|
+
Pairing ${status.status}. Run setup again.`);
|
|
2953
|
+
return void 0;
|
|
2954
|
+
}
|
|
2955
|
+
if (!announced) {
|
|
2956
|
+
console.log(`
|
|
2957
|
+
Confirm in the Ascenda app \u2014 code ${code}`);
|
|
2958
|
+
console.log(" Waiting...");
|
|
2959
|
+
announced = true;
|
|
2960
|
+
}
|
|
2961
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
2962
|
+
}
|
|
2963
|
+
console.error("\nPairing timed out. Run setup again.");
|
|
2964
|
+
return void 0;
|
|
2965
|
+
}
|
|
2966
|
+
function installBinary(spec, dryRun) {
|
|
2967
|
+
const target = cliAgentHookBinPath(spec.binaryName);
|
|
2968
|
+
if (dryRun)
|
|
2969
|
+
return target;
|
|
2970
|
+
const source = process.argv[1];
|
|
2971
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
2972
|
+
if (path.resolve(source) !== path.resolve(target)) {
|
|
2973
|
+
fs.copyFileSync(source, target);
|
|
2974
|
+
}
|
|
2975
|
+
if (process.platform !== "win32")
|
|
2976
|
+
fs.chmodSync(target, 493);
|
|
2977
|
+
return target;
|
|
2978
|
+
}
|
|
2979
|
+
function writeHookSettings(settingsFile, binary, spec, dryRun) {
|
|
2980
|
+
let settings = { ...spec.settings.scaffold ?? {} };
|
|
2981
|
+
const exists = fs.existsSync(settingsFile);
|
|
2982
|
+
if (exists) {
|
|
2983
|
+
const raw = fs.readFileSync(settingsFile, "utf8").trim();
|
|
2984
|
+
if (raw) {
|
|
2985
|
+
try {
|
|
2986
|
+
settings = JSON.parse(raw);
|
|
2987
|
+
} catch {
|
|
2988
|
+
console.error(`
|
|
2989
|
+
${settingsFile} is not valid JSON. Fix or move it, then run setup again.`);
|
|
2990
|
+
return null;
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
const command = hookCommand(binary);
|
|
2995
|
+
const hooks = { ...settings.hooks ?? {} };
|
|
2996
|
+
for (const event of spec.hookEvents) {
|
|
2997
|
+
const kept = (hooks[event] ?? []).filter((entry) => !isOurs(entry, spec));
|
|
2998
|
+
hooks[event] = [...kept, spec.settings.entry(command, event)];
|
|
2999
|
+
}
|
|
3000
|
+
const updated = { ...settings, hooks };
|
|
3001
|
+
const serialised = `${JSON.stringify(updated, null, 2)}
|
|
3002
|
+
`;
|
|
3003
|
+
if (exists && fs.readFileSync(settingsFile, "utf8") === serialised)
|
|
3004
|
+
return false;
|
|
3005
|
+
if (dryRun) {
|
|
3006
|
+
console.log(`
|
|
3007
|
+
--- ${settingsFile} (dry run) ---
|
|
3008
|
+
${serialised}`);
|
|
3009
|
+
return true;
|
|
3010
|
+
}
|
|
3011
|
+
if (exists)
|
|
3012
|
+
fs.copyFileSync(settingsFile, `${settingsFile}.ascenda-backup`);
|
|
3013
|
+
fs.mkdirSync(path.dirname(settingsFile), { recursive: true });
|
|
3014
|
+
fs.writeFileSync(settingsFile, serialised, "utf8");
|
|
3015
|
+
return true;
|
|
3016
|
+
}
|
|
3017
|
+
function hookCommand(binary) {
|
|
3018
|
+
return `"${process.execPath}" "${binary}"`;
|
|
3019
|
+
}
|
|
3020
|
+
function isOurs(entry, spec) {
|
|
3021
|
+
const command = spec.settings.commandOf(entry);
|
|
3022
|
+
return typeof command === "string" && command.includes(spec.binaryName);
|
|
3023
|
+
}
|
|
3024
|
+
function findStaleHookCommands(settings, binary, spec) {
|
|
3025
|
+
const stale = /* @__PURE__ */ new Set();
|
|
3026
|
+
for (const entries of Object.values(settings.hooks ?? {})) {
|
|
3027
|
+
for (const entry of entries ?? []) {
|
|
3028
|
+
const command = spec.settings.commandOf(entry);
|
|
3029
|
+
if (typeof command !== "string")
|
|
3030
|
+
continue;
|
|
3031
|
+
if (!/ascenda/i.test(command) || command.includes(binary))
|
|
3032
|
+
continue;
|
|
3033
|
+
stale.add(command);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
return [...stale];
|
|
3037
|
+
}
|
|
3038
|
+
function readSettings(settingsFile) {
|
|
3039
|
+
try {
|
|
3040
|
+
return JSON.parse(fs.readFileSync(settingsFile, "utf8"));
|
|
3041
|
+
} catch {
|
|
3042
|
+
return {};
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
function printStatus(options, spec) {
|
|
3046
|
+
const credentials = (0, credentials_1.readHostCredentials)(spec.host);
|
|
3047
|
+
const settingsFile = spec.settings.settingsPath(options.scope, options.projectDir);
|
|
3048
|
+
const binary = cliAgentHookBinPath(spec.binaryName);
|
|
3049
|
+
const tokenFile = credentials?.toolInstallationId ? (0, tokenStore_1.defaultTokenFilePath)(credentials.toolInstallationId) : void 0;
|
|
3050
|
+
const settings = readSettings(settingsFile);
|
|
3051
|
+
const registered = spec.hookEvents.filter((event) => (settings.hooks?.[event] ?? []).some((entry) => isOurs(entry, spec))).length;
|
|
3052
|
+
const stale = findStaleHookCommands(settings, binary, spec);
|
|
3053
|
+
console.log(`api base url ${credentials?.apiBaseUrl ?? "\u2014 not configured"}`);
|
|
3054
|
+
console.log(`pairing ${credentials?.toolInstallationId ?? "\u2014 not paired"}`);
|
|
3055
|
+
console.log(`token ${tokenFile && (0, tokenStore_1.readTokenFile)(tokenFile) ? "present" : "\u2014 missing"}`);
|
|
3056
|
+
console.log(`hook binary ${fs.existsSync(binary) ? binary : "\u2014 not installed"}`);
|
|
3057
|
+
console.log(`hooks ${registered}/${spec.hookEvents.length} registered in ${settingsFile}`);
|
|
3058
|
+
if (stale.length) {
|
|
3059
|
+
console.log(`stale hooks ${stale.length} not pointing at the installed binary \u2014 each one fails silently per event:`);
|
|
3060
|
+
for (const command of stale)
|
|
3061
|
+
console.log(` ${command}`);
|
|
3062
|
+
console.log(` Remove them from ${settingsFile} by hand; setup cannot tell them from a hook you wrote.`);
|
|
3063
|
+
}
|
|
3064
|
+
const healthy = credentials?.toolInstallationId && registered === spec.hookEvents.length && fs.existsSync(binary) && !stale.length;
|
|
3065
|
+
return healthy ? 0 : 1;
|
|
3066
|
+
}
|
|
3067
|
+
function uninstall(options, spec) {
|
|
3068
|
+
const settingsFile = spec.settings.settingsPath(options.scope, options.projectDir);
|
|
3069
|
+
if (fs.existsSync(settingsFile)) {
|
|
3070
|
+
try {
|
|
3071
|
+
const settings = JSON.parse(fs.readFileSync(settingsFile, "utf8"));
|
|
3072
|
+
const hooks = { ...settings.hooks ?? {} };
|
|
3073
|
+
for (const event of Object.keys(hooks)) {
|
|
3074
|
+
const kept = hooks[event].filter((entry) => !isOurs(entry, spec));
|
|
3075
|
+
if (kept.length)
|
|
3076
|
+
hooks[event] = kept;
|
|
3077
|
+
else
|
|
3078
|
+
delete hooks[event];
|
|
3079
|
+
}
|
|
3080
|
+
const updated = { ...settings, hooks };
|
|
3081
|
+
if (!Object.keys(hooks).length)
|
|
3082
|
+
delete updated.hooks;
|
|
3083
|
+
fs.copyFileSync(settingsFile, `${settingsFile}.ascenda-backup`);
|
|
3084
|
+
fs.writeFileSync(settingsFile, `${JSON.stringify(updated, null, 2)}
|
|
3085
|
+
`, "utf8");
|
|
3086
|
+
console.log(`hooks removed from ${settingsFile}`);
|
|
3087
|
+
} catch {
|
|
3088
|
+
console.error(`could not parse ${settingsFile} \u2014 remove the ascenda hook entries by hand`);
|
|
3089
|
+
return 1;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
const binary = cliAgentHookBinPath(spec.binaryName);
|
|
3093
|
+
if (fs.existsSync(binary)) {
|
|
3094
|
+
fs.rmSync(binary);
|
|
3095
|
+
console.log(`removed ${binary}`);
|
|
3096
|
+
}
|
|
3097
|
+
if ((0, credentials_1.readHostCredentials)(spec.host)) {
|
|
3098
|
+
(0, credentials_1.removeHostCredentials)(spec.host);
|
|
3099
|
+
console.log(`removed tools.${spec.host} from ${(0, credentials_1.credentialsFilePath)()}`);
|
|
3100
|
+
}
|
|
3101
|
+
console.log(`tokens left in ${path.join((0, tokenStore_1.ascendaHome)(), "tokens")} \u2014 revoke in the Ascenda app to invalidate them`);
|
|
3102
|
+
return 0;
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
});
|
|
3106
|
+
|
|
1667
3107
|
// ../packages/tool-kit/out/turnState.js
|
|
1668
3108
|
var require_turnState = __commonJS({
|
|
1669
3109
|
"../packages/tool-kit/out/turnState.js"(exports) {
|
|
@@ -1877,8 +3317,9 @@ var require_out2 = __commonJS({
|
|
|
1877
3317
|
"../packages/tool-kit/out/index.js"(exports) {
|
|
1878
3318
|
"use strict";
|
|
1879
3319
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1880
|
-
exports.
|
|
1881
|
-
exports.
|
|
3320
|
+
exports.consumeTurnDurationMs = exports.writeTopLevelCredentials = exports.writeMachineCredentials = exports.writeHostCredentials = exports.removeHostCredentials = exports.readMachineCredentials = exports.readHostCredentials = exports.credentialsFilePath = exports.writeHookSettings = exports.runCliAgentSetup = exports.isCliAgentManagementCommand = exports.findStaleHookCommands = exports.cliAgentHookBinPath = exports.resolveContextHashes = exports.resolveCliAgentInstallationId = exports.loadCliAgentConfig = exports.deliverHookEvents = exports.MissingInstallationIdError = exports.DEFAULT_API_BASE_URL = exports.resolveEventLogPath = exports.expandUserPath = exports.appendEventLog = exports.EVENT_LOG_ENV_VAR = exports.buildEventPayload = exports.AscendaSemanticEventError = exports.AscendaEventSender = exports.mintIdempotencyKey = exports.looksLikeCorrection = exports.outcomeForHook = exports.inferOutcome = exports.getNestedNumber = exports.getNestedString = exports.getNested = exports.getNumber = exports.getString = exports.localHourAt = exports.utcOffsetMinutesAt = exports.BUSINESS_DAY = exports.isOutsideBusinessHours = exports.isAfterHours = exports.bucketDurationMs = exports.bucketLinesChanged = exports.classifyModelClass = exports.autonomyBand = exports.invitesDebrief = exports.classifyWorkMilestone = exports.isReworkGitAction = exports.classifyGitAction = exports.isVerificationCommand = exports.classifyCommand = void 0;
|
|
3321
|
+
exports.postToolEvent = exports.renewToolToken = exports.getPairingStatus = exports.createPairingSession = exports.AscendaApiError = exports.liveBusSocketCandidates = exports.liveBusSocketPath = exports.bucketPromptSize = exports.emitLiveSignal = exports.recordForgeProjectAlias = exports.forgeFullNameFromConfig = exports.readForgeFullName = exports.parseForgeFullName = exports.forgeProjectHash = exports.workContextRegistryFilePath = exports.readWorkContextRegistry = exports.recordWorkContextAlias = exports.recordWorkContext = exports.readBranchName = exports.normalizeBranchName = exports.deriveBranchHashForCwd = exports.deriveBranchHash = exports.deriveWorkContext = exports.hashWithMachineSalt = exports.readOrCreateMachineSalt = exports.machineSaltFilePath = exports.enforceOutboxBounds = exports.claimOutbox = exports.readOutboxSummary = exports.appendToOutbox = exports.defaultOutboxFilePath = exports.outboxDrainEnabled = exports.DEFAULT_OUTBOX_DRAIN_BATCH_SIZE = exports.DEFAULT_OUTBOX_MAX_AGE_MS = exports.DEFAULT_OUTBOX_MAX_ENTRIES = exports.OUTBOX_DRAIN_ENV_VAR = exports.recordOutboxDiscard = exports.unresolvedToolInstallationId = exports.unresolvedStateFilePath = exports.markFailureNotified = exports.shouldAnnounceFailure = exports.recordSendOutcome = exports.readCollectorState = exports.defaultStateFilePath = exports.readTokenFile = exports.persistEventWriteToken = exports.listPersistedToolInstallationIds = exports.defaultTokenFilePath = exports.ascendaHome = exports.recordTurnStart = void 0;
|
|
3322
|
+
exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = void 0;
|
|
1882
3323
|
var commandClassifier_1 = require_commandClassifier();
|
|
1883
3324
|
Object.defineProperty(exports, "classifyCommand", { enumerable: true, get: function() {
|
|
1884
3325
|
return commandClassifier_1.classifyCommand;
|
|
@@ -1900,6 +3341,14 @@ var require_out2 = __commonJS({
|
|
|
1900
3341
|
Object.defineProperty(exports, "invitesDebrief", { enumerable: true, get: function() {
|
|
1901
3342
|
return workMilestoneClassifier_1.invitesDebrief;
|
|
1902
3343
|
} });
|
|
3344
|
+
var autonomyBand_1 = require_autonomyBand();
|
|
3345
|
+
Object.defineProperty(exports, "autonomyBand", { enumerable: true, get: function() {
|
|
3346
|
+
return autonomyBand_1.autonomyBand;
|
|
3347
|
+
} });
|
|
3348
|
+
var modelClassifier_1 = require_modelClassifier();
|
|
3349
|
+
Object.defineProperty(exports, "classifyModelClass", { enumerable: true, get: function() {
|
|
3350
|
+
return modelClassifier_1.classifyModelClass;
|
|
3351
|
+
} });
|
|
1903
3352
|
var buckets_1 = require_buckets();
|
|
1904
3353
|
Object.defineProperty(exports, "bucketLinesChanged", { enumerable: true, get: function() {
|
|
1905
3354
|
return buckets_1.bucketLinesChanged;
|
|
@@ -1948,6 +3397,9 @@ var require_out2 = __commonJS({
|
|
|
1948
3397
|
Object.defineProperty(exports, "looksLikeCorrection", { enumerable: true, get: function() {
|
|
1949
3398
|
return payload_1.looksLikeCorrection;
|
|
1950
3399
|
} });
|
|
3400
|
+
Object.defineProperty(exports, "mintIdempotencyKey", { enumerable: true, get: function() {
|
|
3401
|
+
return payload_1.mintIdempotencyKey;
|
|
3402
|
+
} });
|
|
1951
3403
|
var eventSender_1 = require_eventSender();
|
|
1952
3404
|
Object.defineProperty(exports, "AscendaEventSender", { enumerable: true, get: function() {
|
|
1953
3405
|
return eventSender_1.AscendaEventSender;
|
|
@@ -1975,15 +3427,59 @@ var require_out2 = __commonJS({
|
|
|
1975
3427
|
Object.defineProperty(exports, "DEFAULT_API_BASE_URL", { enumerable: true, get: function() {
|
|
1976
3428
|
return hookAdapter_1.DEFAULT_API_BASE_URL;
|
|
1977
3429
|
} });
|
|
3430
|
+
Object.defineProperty(exports, "MissingInstallationIdError", { enumerable: true, get: function() {
|
|
3431
|
+
return hookAdapter_1.MissingInstallationIdError;
|
|
3432
|
+
} });
|
|
1978
3433
|
Object.defineProperty(exports, "deliverHookEvents", { enumerable: true, get: function() {
|
|
1979
3434
|
return hookAdapter_1.deliverHookEvents;
|
|
1980
3435
|
} });
|
|
1981
3436
|
Object.defineProperty(exports, "loadCliAgentConfig", { enumerable: true, get: function() {
|
|
1982
3437
|
return hookAdapter_1.loadCliAgentConfig;
|
|
1983
3438
|
} });
|
|
3439
|
+
Object.defineProperty(exports, "resolveCliAgentInstallationId", { enumerable: true, get: function() {
|
|
3440
|
+
return hookAdapter_1.resolveCliAgentInstallationId;
|
|
3441
|
+
} });
|
|
1984
3442
|
Object.defineProperty(exports, "resolveContextHashes", { enumerable: true, get: function() {
|
|
1985
3443
|
return hookAdapter_1.resolveContextHashes;
|
|
1986
3444
|
} });
|
|
3445
|
+
var cliAgentSetup_1 = require_cliAgentSetup();
|
|
3446
|
+
Object.defineProperty(exports, "cliAgentHookBinPath", { enumerable: true, get: function() {
|
|
3447
|
+
return cliAgentSetup_1.cliAgentHookBinPath;
|
|
3448
|
+
} });
|
|
3449
|
+
Object.defineProperty(exports, "findStaleHookCommands", { enumerable: true, get: function() {
|
|
3450
|
+
return cliAgentSetup_1.findStaleHookCommands;
|
|
3451
|
+
} });
|
|
3452
|
+
Object.defineProperty(exports, "isCliAgentManagementCommand", { enumerable: true, get: function() {
|
|
3453
|
+
return cliAgentSetup_1.isCliAgentManagementCommand;
|
|
3454
|
+
} });
|
|
3455
|
+
Object.defineProperty(exports, "runCliAgentSetup", { enumerable: true, get: function() {
|
|
3456
|
+
return cliAgentSetup_1.runCliAgentSetup;
|
|
3457
|
+
} });
|
|
3458
|
+
Object.defineProperty(exports, "writeHookSettings", { enumerable: true, get: function() {
|
|
3459
|
+
return cliAgentSetup_1.writeHookSettings;
|
|
3460
|
+
} });
|
|
3461
|
+
var credentials_1 = require_credentials();
|
|
3462
|
+
Object.defineProperty(exports, "credentialsFilePath", { enumerable: true, get: function() {
|
|
3463
|
+
return credentials_1.credentialsFilePath;
|
|
3464
|
+
} });
|
|
3465
|
+
Object.defineProperty(exports, "readHostCredentials", { enumerable: true, get: function() {
|
|
3466
|
+
return credentials_1.readHostCredentials;
|
|
3467
|
+
} });
|
|
3468
|
+
Object.defineProperty(exports, "readMachineCredentials", { enumerable: true, get: function() {
|
|
3469
|
+
return credentials_1.readMachineCredentials;
|
|
3470
|
+
} });
|
|
3471
|
+
Object.defineProperty(exports, "removeHostCredentials", { enumerable: true, get: function() {
|
|
3472
|
+
return credentials_1.removeHostCredentials;
|
|
3473
|
+
} });
|
|
3474
|
+
Object.defineProperty(exports, "writeHostCredentials", { enumerable: true, get: function() {
|
|
3475
|
+
return credentials_1.writeHostCredentials;
|
|
3476
|
+
} });
|
|
3477
|
+
Object.defineProperty(exports, "writeMachineCredentials", { enumerable: true, get: function() {
|
|
3478
|
+
return credentials_1.writeMachineCredentials;
|
|
3479
|
+
} });
|
|
3480
|
+
Object.defineProperty(exports, "writeTopLevelCredentials", { enumerable: true, get: function() {
|
|
3481
|
+
return credentials_1.writeTopLevelCredentials;
|
|
3482
|
+
} });
|
|
1987
3483
|
var turnState_1 = require_turnState();
|
|
1988
3484
|
Object.defineProperty(exports, "consumeTurnDurationMs", { enumerable: true, get: function() {
|
|
1989
3485
|
return turnState_1.consumeTurnDurationMs;
|
|
@@ -1998,6 +3494,9 @@ var require_out2 = __commonJS({
|
|
|
1998
3494
|
Object.defineProperty(exports, "defaultTokenFilePath", { enumerable: true, get: function() {
|
|
1999
3495
|
return tokenStore_1.defaultTokenFilePath;
|
|
2000
3496
|
} });
|
|
3497
|
+
Object.defineProperty(exports, "listPersistedToolInstallationIds", { enumerable: true, get: function() {
|
|
3498
|
+
return tokenStore_1.listPersistedToolInstallationIds;
|
|
3499
|
+
} });
|
|
2001
3500
|
Object.defineProperty(exports, "persistEventWriteToken", { enumerable: true, get: function() {
|
|
2002
3501
|
return tokenStore_1.persistEventWriteToken;
|
|
2003
3502
|
} });
|
|
@@ -2020,6 +3519,46 @@ var require_out2 = __commonJS({
|
|
|
2020
3519
|
Object.defineProperty(exports, "markFailureNotified", { enumerable: true, get: function() {
|
|
2021
3520
|
return stateStore_1.markFailureNotified;
|
|
2022
3521
|
} });
|
|
3522
|
+
Object.defineProperty(exports, "unresolvedStateFilePath", { enumerable: true, get: function() {
|
|
3523
|
+
return stateStore_1.unresolvedStateFilePath;
|
|
3524
|
+
} });
|
|
3525
|
+
Object.defineProperty(exports, "unresolvedToolInstallationId", { enumerable: true, get: function() {
|
|
3526
|
+
return stateStore_1.unresolvedToolInstallationId;
|
|
3527
|
+
} });
|
|
3528
|
+
Object.defineProperty(exports, "recordOutboxDiscard", { enumerable: true, get: function() {
|
|
3529
|
+
return stateStore_1.recordOutboxDiscard;
|
|
3530
|
+
} });
|
|
3531
|
+
var outbox_1 = require_outbox();
|
|
3532
|
+
Object.defineProperty(exports, "OUTBOX_DRAIN_ENV_VAR", { enumerable: true, get: function() {
|
|
3533
|
+
return outbox_1.OUTBOX_DRAIN_ENV_VAR;
|
|
3534
|
+
} });
|
|
3535
|
+
Object.defineProperty(exports, "DEFAULT_OUTBOX_MAX_ENTRIES", { enumerable: true, get: function() {
|
|
3536
|
+
return outbox_1.DEFAULT_OUTBOX_MAX_ENTRIES;
|
|
3537
|
+
} });
|
|
3538
|
+
Object.defineProperty(exports, "DEFAULT_OUTBOX_MAX_AGE_MS", { enumerable: true, get: function() {
|
|
3539
|
+
return outbox_1.DEFAULT_OUTBOX_MAX_AGE_MS;
|
|
3540
|
+
} });
|
|
3541
|
+
Object.defineProperty(exports, "DEFAULT_OUTBOX_DRAIN_BATCH_SIZE", { enumerable: true, get: function() {
|
|
3542
|
+
return outbox_1.DEFAULT_OUTBOX_DRAIN_BATCH_SIZE;
|
|
3543
|
+
} });
|
|
3544
|
+
Object.defineProperty(exports, "outboxDrainEnabled", { enumerable: true, get: function() {
|
|
3545
|
+
return outbox_1.outboxDrainEnabled;
|
|
3546
|
+
} });
|
|
3547
|
+
Object.defineProperty(exports, "defaultOutboxFilePath", { enumerable: true, get: function() {
|
|
3548
|
+
return outbox_1.defaultOutboxFilePath;
|
|
3549
|
+
} });
|
|
3550
|
+
Object.defineProperty(exports, "appendToOutbox", { enumerable: true, get: function() {
|
|
3551
|
+
return outbox_1.appendToOutbox;
|
|
3552
|
+
} });
|
|
3553
|
+
Object.defineProperty(exports, "readOutboxSummary", { enumerable: true, get: function() {
|
|
3554
|
+
return outbox_1.readOutboxSummary;
|
|
3555
|
+
} });
|
|
3556
|
+
Object.defineProperty(exports, "claimOutbox", { enumerable: true, get: function() {
|
|
3557
|
+
return outbox_1.claimOutbox;
|
|
3558
|
+
} });
|
|
3559
|
+
Object.defineProperty(exports, "enforceOutboxBounds", { enumerable: true, get: function() {
|
|
3560
|
+
return outbox_1.enforceOutboxBounds;
|
|
3561
|
+
} });
|
|
2023
3562
|
var salt_1 = require_salt();
|
|
2024
3563
|
Object.defineProperty(exports, "machineSaltFilePath", { enumerable: true, get: function() {
|
|
2025
3564
|
return salt_1.machineSaltFilePath;
|
|
@@ -2034,6 +3573,18 @@ var require_out2 = __commonJS({
|
|
|
2034
3573
|
Object.defineProperty(exports, "deriveWorkContext", { enumerable: true, get: function() {
|
|
2035
3574
|
return workContext_1.deriveWorkContext;
|
|
2036
3575
|
} });
|
|
3576
|
+
Object.defineProperty(exports, "deriveBranchHash", { enumerable: true, get: function() {
|
|
3577
|
+
return workContext_1.deriveBranchHash;
|
|
3578
|
+
} });
|
|
3579
|
+
Object.defineProperty(exports, "deriveBranchHashForCwd", { enumerable: true, get: function() {
|
|
3580
|
+
return workContext_1.deriveBranchHashForCwd;
|
|
3581
|
+
} });
|
|
3582
|
+
Object.defineProperty(exports, "normalizeBranchName", { enumerable: true, get: function() {
|
|
3583
|
+
return workContext_1.normalizeBranchName;
|
|
3584
|
+
} });
|
|
3585
|
+
Object.defineProperty(exports, "readBranchName", { enumerable: true, get: function() {
|
|
3586
|
+
return workContext_1.readBranchName;
|
|
3587
|
+
} });
|
|
2037
3588
|
var contextRegistry_1 = require_contextRegistry();
|
|
2038
3589
|
Object.defineProperty(exports, "recordWorkContext", { enumerable: true, get: function() {
|
|
2039
3590
|
return contextRegistry_1.recordWorkContext;
|
|
@@ -2047,6 +3598,22 @@ var require_out2 = __commonJS({
|
|
|
2047
3598
|
Object.defineProperty(exports, "workContextRegistryFilePath", { enumerable: true, get: function() {
|
|
2048
3599
|
return contextRegistry_1.workContextRegistryFilePath;
|
|
2049
3600
|
} });
|
|
3601
|
+
var forgeProject_1 = require_forgeProject();
|
|
3602
|
+
Object.defineProperty(exports, "forgeProjectHash", { enumerable: true, get: function() {
|
|
3603
|
+
return forgeProject_1.forgeProjectHash;
|
|
3604
|
+
} });
|
|
3605
|
+
Object.defineProperty(exports, "parseForgeFullName", { enumerable: true, get: function() {
|
|
3606
|
+
return forgeProject_1.parseForgeFullName;
|
|
3607
|
+
} });
|
|
3608
|
+
Object.defineProperty(exports, "readForgeFullName", { enumerable: true, get: function() {
|
|
3609
|
+
return forgeProject_1.readForgeFullName;
|
|
3610
|
+
} });
|
|
3611
|
+
Object.defineProperty(exports, "forgeFullNameFromConfig", { enumerable: true, get: function() {
|
|
3612
|
+
return forgeProject_1.forgeFullNameFromConfig;
|
|
3613
|
+
} });
|
|
3614
|
+
Object.defineProperty(exports, "recordForgeProjectAlias", { enumerable: true, get: function() {
|
|
3615
|
+
return forgeProject_1.recordForgeProjectAlias;
|
|
3616
|
+
} });
|
|
2050
3617
|
var liveBus_1 = require_liveBus();
|
|
2051
3618
|
Object.defineProperty(exports, "emitLiveSignal", { enumerable: true, get: function() {
|
|
2052
3619
|
return liveBus_1.emitLiveSignal;
|
|
@@ -2089,7 +3656,7 @@ var require_out2 = __commonJS({
|
|
|
2089
3656
|
});
|
|
2090
3657
|
|
|
2091
3658
|
// src/cli.ts
|
|
2092
|
-
var
|
|
3659
|
+
var import_tool_kit3 = __toESM(require_out2(), 1);
|
|
2093
3660
|
import { readFile } from "node:fs/promises";
|
|
2094
3661
|
|
|
2095
3662
|
// src/config.ts
|
|
@@ -2119,6 +3686,7 @@ function normalizeToolInstallationId(value) {
|
|
|
2119
3686
|
}
|
|
2120
3687
|
|
|
2121
3688
|
// src/mapForgeEvent.ts
|
|
3689
|
+
var import_tool_kit2 = __toESM(require_out2(), 1);
|
|
2122
3690
|
function mapForgeEvent(eventName, payload, viewerLogin) {
|
|
2123
3691
|
if (!eventName || !viewerLogin) return [];
|
|
2124
3692
|
const action = str(payload["action"]);
|
|
@@ -2170,20 +3738,20 @@ function base(payload) {
|
|
|
2170
3738
|
host: "github",
|
|
2171
3739
|
// Hashed, never the name. "Is it always the same repository" stays
|
|
2172
3740
|
// answerable; which repository does not travel.
|
|
2173
|
-
|
|
3741
|
+
//
|
|
3742
|
+
// The digest is an UNSALTED FNV-1a of `owner/repo`, and this step stays
|
|
3743
|
+
// deliberately salt-free: it runs in CI from a webhook payload, where the
|
|
3744
|
+
// only place a machine salt could come from is a repository secret — which
|
|
3745
|
+
// is to say, from everyone who can read the repository's settings. The
|
|
3746
|
+
// function now lives in tool-kit so a developer's own machine, which holds
|
|
3747
|
+
// both identities, can compute this exact digest and file it beside its
|
|
3748
|
+
// own; nothing about what this step emits has changed.
|
|
3749
|
+
...repo ? { projectHash: (0, import_tool_kit2.forgeProjectHash)(repo) } : {}
|
|
2174
3750
|
};
|
|
2175
3751
|
}
|
|
2176
3752
|
function reviewState(state) {
|
|
2177
3753
|
return state?.toLowerCase() === "approved" ? "success" : "unknown";
|
|
2178
3754
|
}
|
|
2179
|
-
function hash(value) {
|
|
2180
|
-
let h = 2166136261;
|
|
2181
|
-
for (let i = 0; i < value.length; i++) {
|
|
2182
|
-
h ^= value.charCodeAt(i);
|
|
2183
|
-
h = Math.imul(h, 16777619) >>> 0;
|
|
2184
|
-
}
|
|
2185
|
-
return h.toString(16).padStart(8, "0");
|
|
2186
|
-
}
|
|
2187
3755
|
function obj(value) {
|
|
2188
3756
|
return value && typeof value === "object" ? value : {};
|
|
2189
3757
|
}
|
|
@@ -2199,7 +3767,7 @@ async function main() {
|
|
|
2199
3767
|
if (!payload) return;
|
|
2200
3768
|
const events = mapForgeEvent(eventName, payload, config.viewerLogin);
|
|
2201
3769
|
if (events.length === 0) return;
|
|
2202
|
-
const sender = new
|
|
3770
|
+
const sender = new import_tool_kit3.AscendaEventSender({
|
|
2203
3771
|
apiBaseUrl: config.apiBaseUrl,
|
|
2204
3772
|
toolInstallationId: config.toolInstallationId,
|
|
2205
3773
|
source: "code_forge",
|