@ascenda-one/github-collector 0.1.11 → 0.1.13

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.
Files changed (2) hide show
  1. package/dist/cli.js +448 -90
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -242,7 +242,28 @@ var require_afterHours = __commonJS({
242
242
  "../packages/tool-kit/out/afterHours.js"(exports) {
243
243
  "use strict";
244
244
  Object.defineProperty(exports, "__esModule", { value: true });
245
+ exports.BUSINESS_DAY = void 0;
246
+ exports.isOutsideBusinessHours = isOutsideBusinessHours;
245
247
  exports.isAfterHours = isAfterHours;
248
+ exports.utcOffsetMinutesAt = utcOffsetMinutesAt;
249
+ exports.localHourAt = localHourAt;
250
+ exports.BUSINESS_DAY = {
251
+ /** 0 = Sunday … 6 = Saturday. */
252
+ days: [1, 2, 3, 4, 5],
253
+ start: "09:00",
254
+ end: "17:00"
255
+ };
256
+ function isOutsideBusinessHours(at = /* @__PURE__ */ new Date(), opts = {}) {
257
+ const days = opts.days ?? exports.BUSINESS_DAY.days;
258
+ if (!days.includes(at.getDay()))
259
+ return true;
260
+ const minutes = at.getHours() * 60 + at.getMinutes();
261
+ const start = parseTimeToMinutes(opts.start ?? exports.BUSINESS_DAY.start, 9 * 60);
262
+ const end = parseTimeToMinutes(opts.end ?? exports.BUSINESS_DAY.end, 17 * 60);
263
+ if (start >= end)
264
+ return false;
265
+ return minutes < start || minutes >= end;
266
+ }
246
267
  function isAfterHours(now = /* @__PURE__ */ new Date(), start = "19:00", end = "07:00") {
247
268
  const currentMinutes = now.getHours() * 60 + now.getMinutes();
248
269
  const startMinutes = parseTimeToMinutes(start, 19 * 60);
@@ -263,6 +284,13 @@ var require_afterHours = __commonJS({
263
284
  return fallback;
264
285
  return Math.max(0, Math.min(23, hours)) * 60 + Math.max(0, Math.min(59, minutes));
265
286
  }
287
+ function utcOffsetMinutesAt(at) {
288
+ return -at.getTimezoneOffset();
289
+ }
290
+ function localHourAt(at, utcOffsetMinutes) {
291
+ const shifted = new Date(at.getTime() + utcOffsetMinutes * 6e4);
292
+ return shifted.getUTCHours();
293
+ }
266
294
  }
267
295
  });
268
296
 
@@ -354,7 +382,7 @@ var require_out = __commonJS({
354
382
  "../packages/tool-contract/out/index.js"(exports) {
355
383
  "use strict";
356
384
  Object.defineProperty(exports, "__esModule", { value: true });
357
- exports.ASCENDA_SEMANTIC_PROVENANCE = 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;
385
+ 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;
358
386
  exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = [
359
387
  "approach_churn_detected",
360
388
  "goal_drift_detected",
@@ -411,6 +439,7 @@ var require_out = __commonJS({
411
439
  exports.ASCENDA_PROVENANCE = "ai_work_telemetry";
412
440
  exports.ASCENDA_SEMANTIC_CONSENT_SCOPE = "semantic_work_signals";
413
441
  exports.ASCENDA_COLLABORATION_CONSENT_SCOPE = "workflow_telemetry";
442
+ exports.ASCENDA_HISTORICAL_CONSENT_SCOPE = "historical_import";
414
443
  exports.ASCENDA_SEMANTIC_PROVENANCE = "semantic_work_signals";
415
444
  }
416
445
  });
@@ -816,6 +845,7 @@ var require_eventSender = __commonJS({
816
845
  Object.defineProperty(exports, "__esModule", { value: true });
817
846
  exports.AscendaEventSender = exports.AscendaSemanticEventError = void 0;
818
847
  exports.buildEventPayload = buildEventPayload;
848
+ var afterHours_1 = require_afterHours();
819
849
  var tool_contract_1 = require_out();
820
850
  var eventLog_1 = require_eventLog();
821
851
  var http_1 = require_http();
@@ -833,8 +863,10 @@ var require_eventSender = __commonJS({
833
863
  toolInstallationId: identity.toolInstallationId,
834
864
  source: identity.source,
835
865
  occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
866
+ utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
836
867
  sessionId: identity.sessionId ?? void 0,
837
868
  workspaceHash: identity.workspaceHash ?? void 0,
869
+ projectHash: identity.projectHash ?? void 0,
838
870
  consentScope: tool_contract_1.ASCENDA_CONSENT_SCOPE,
839
871
  provenance: tool_contract_1.ASCENDA_PROVENANCE,
840
872
  privacyMode: "metadata_only",
@@ -886,9 +918,11 @@ var require_eventSender = __commonJS({
886
918
  source: this.config.source,
887
919
  eventType: mapped.eventType,
888
920
  occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
921
+ utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
889
922
  severity: "low",
890
923
  sessionId: this.config.sessionId ?? void 0,
891
924
  workspaceHash: this.config.workspaceHash ?? void 0,
925
+ projectHash: this.config.projectHash ?? void 0,
892
926
  consentScope: tool_contract_1.ASCENDA_SEMANTIC_CONSENT_SCOPE,
893
927
  provenance: tool_contract_1.ASCENDA_SEMANTIC_PROVENANCE,
894
928
  privacyMode: "metadata_only",
@@ -914,9 +948,11 @@ var require_eventSender = __commonJS({
914
948
  source: this.config.source,
915
949
  eventType: mapped.eventType,
916
950
  occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
951
+ utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
917
952
  severity: "low",
918
953
  sessionId: this.config.sessionId ?? void 0,
919
954
  workspaceHash: this.config.workspaceHash ?? void 0,
955
+ projectHash: this.config.projectHash ?? void 0,
920
956
  consentScope: tool_contract_1.ASCENDA_COLLABORATION_CONSENT_SCOPE,
921
957
  provenance: tool_contract_1.ASCENDA_PROVENANCE,
922
958
  privacyMode: "metadata_only",
@@ -1007,19 +1043,387 @@ var require_eventSender = __commonJS({
1007
1043
  }
1008
1044
  });
1009
1045
 
1046
+ // ../packages/tool-kit/out/contextRegistry.js
1047
+ var require_contextRegistry = __commonJS({
1048
+ "../packages/tool-kit/out/contextRegistry.js"(exports) {
1049
+ "use strict";
1050
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1051
+ if (k2 === void 0) k2 = k;
1052
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1053
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1054
+ desc = { enumerable: true, get: function() {
1055
+ return m[k];
1056
+ } };
1057
+ }
1058
+ Object.defineProperty(o, k2, desc);
1059
+ } : function(o, m, k, k2) {
1060
+ if (k2 === void 0) k2 = k;
1061
+ o[k2] = m[k];
1062
+ });
1063
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1064
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1065
+ } : function(o, v) {
1066
+ o["default"] = v;
1067
+ });
1068
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1069
+ var ownKeys = function(o) {
1070
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
1071
+ var ar = [];
1072
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1073
+ return ar;
1074
+ };
1075
+ return ownKeys(o);
1076
+ };
1077
+ return function(mod) {
1078
+ if (mod && mod.__esModule) return mod;
1079
+ var result = {};
1080
+ if (mod != null) {
1081
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1082
+ }
1083
+ __setModuleDefault(result, mod);
1084
+ return result;
1085
+ };
1086
+ }();
1087
+ Object.defineProperty(exports, "__esModule", { value: true });
1088
+ exports.workContextRegistryFilePath = workContextRegistryFilePath;
1089
+ exports.readWorkContextRegistry = readWorkContextRegistry;
1090
+ exports.recordWorkContext = recordWorkContext;
1091
+ exports.recordWorkContextAlias = recordWorkContextAlias;
1092
+ var fs = __importStar(__require("fs"));
1093
+ var os = __importStar(__require("os"));
1094
+ var path = __importStar(__require("path"));
1095
+ var MAX_PATHS_PER_ENTRY = 8;
1096
+ function workContextRegistryFilePath() {
1097
+ return path.join(os.homedir(), ".ascenda", "work-contexts.json");
1098
+ }
1099
+ function readWorkContextRegistry(registryFilePath = workContextRegistryFilePath()) {
1100
+ try {
1101
+ const parsed = JSON.parse(fs.readFileSync(registryFilePath, "utf8"));
1102
+ if (parsed && parsed.version === 1 && parsed.contexts && typeof parsed.contexts === "object") {
1103
+ return parsed;
1104
+ }
1105
+ } catch {
1106
+ }
1107
+ return { version: 1, contexts: {} };
1108
+ }
1109
+ function recordWorkContext(context, options) {
1110
+ if (!context)
1111
+ return false;
1112
+ const updates = [];
1113
+ if (context.projectHash && context.projectLabel) {
1114
+ updates.push({ hash: context.projectHash, kind: "project", label: context.projectLabel, observedPath: context.projectPath ?? context.workspacePath });
1115
+ }
1116
+ if (context.workspaceHash && context.workspaceLabel && context.workspaceHash !== context.projectHash) {
1117
+ updates.push({ hash: context.workspaceHash, kind: "workspace", label: context.workspaceLabel, observedPath: context.workspacePath });
1118
+ }
1119
+ return upsert(updates, options);
1120
+ }
1121
+ function recordWorkContextAlias(hash2, label, observedPath, options) {
1122
+ if (!hash2 || !label)
1123
+ return false;
1124
+ return upsert([{ hash: hash2, kind: "alias", label, observedPath: observedPath ?? null }], options);
1125
+ }
1126
+ function upsert(updates, options) {
1127
+ if (updates.length === 0)
1128
+ return false;
1129
+ try {
1130
+ const registryFilePath = options?.registryFilePath ?? workContextRegistryFilePath();
1131
+ const nowIso = (options?.now ?? /* @__PURE__ */ new Date()).toISOString();
1132
+ const registry = readWorkContextRegistry(registryFilePath);
1133
+ let dirty = false;
1134
+ for (const update of updates) {
1135
+ const existing = registry.contexts[update.hash];
1136
+ if (!existing) {
1137
+ registry.contexts[update.hash] = {
1138
+ kind: update.kind,
1139
+ label: update.label,
1140
+ paths: update.observedPath ? [update.observedPath] : [],
1141
+ firstSeenAt: nowIso,
1142
+ lastSeenAt: nowIso
1143
+ };
1144
+ dirty = true;
1145
+ continue;
1146
+ }
1147
+ if (existing.kind === "alias" && update.kind !== "alias") {
1148
+ existing.kind = update.kind;
1149
+ dirty = true;
1150
+ }
1151
+ if (existing.label !== update.label && update.kind !== "alias") {
1152
+ existing.label = update.label;
1153
+ dirty = true;
1154
+ }
1155
+ if (update.observedPath && !existing.paths.includes(update.observedPath)) {
1156
+ if (existing.paths.length < MAX_PATHS_PER_ENTRY)
1157
+ existing.paths.push(update.observedPath);
1158
+ dirty = true;
1159
+ }
1160
+ if (dayOf(existing.lastSeenAt) !== dayOf(nowIso)) {
1161
+ existing.lastSeenAt = nowIso;
1162
+ dirty = true;
1163
+ }
1164
+ }
1165
+ if (!dirty)
1166
+ return false;
1167
+ writeRegistry(registryFilePath, registry);
1168
+ return true;
1169
+ } catch {
1170
+ return false;
1171
+ }
1172
+ }
1173
+ function dayOf(iso) {
1174
+ return iso.slice(0, 10);
1175
+ }
1176
+ function writeRegistry(registryFilePath, registry) {
1177
+ const dir = path.dirname(registryFilePath);
1178
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
1179
+ const tmp = `${registryFilePath}.${process.pid}.tmp`;
1180
+ fs.writeFileSync(tmp, `${JSON.stringify(registry, null, 2)}
1181
+ `, { encoding: "utf8", mode: 384 });
1182
+ fs.renameSync(tmp, registryFilePath);
1183
+ if (process.platform !== "win32") {
1184
+ fs.chmodSync(registryFilePath, 384);
1185
+ }
1186
+ }
1187
+ }
1188
+ });
1189
+
1190
+ // ../packages/tool-kit/out/salt.js
1191
+ var require_salt = __commonJS({
1192
+ "../packages/tool-kit/out/salt.js"(exports) {
1193
+ "use strict";
1194
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1195
+ if (k2 === void 0) k2 = k;
1196
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1197
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1198
+ desc = { enumerable: true, get: function() {
1199
+ return m[k];
1200
+ } };
1201
+ }
1202
+ Object.defineProperty(o, k2, desc);
1203
+ } : function(o, m, k, k2) {
1204
+ if (k2 === void 0) k2 = k;
1205
+ o[k2] = m[k];
1206
+ });
1207
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1208
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1209
+ } : function(o, v) {
1210
+ o["default"] = v;
1211
+ });
1212
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1213
+ var ownKeys = function(o) {
1214
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
1215
+ var ar = [];
1216
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1217
+ return ar;
1218
+ };
1219
+ return ownKeys(o);
1220
+ };
1221
+ return function(mod) {
1222
+ if (mod && mod.__esModule) return mod;
1223
+ var result = {};
1224
+ if (mod != null) {
1225
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1226
+ }
1227
+ __setModuleDefault(result, mod);
1228
+ return result;
1229
+ };
1230
+ }();
1231
+ Object.defineProperty(exports, "__esModule", { value: true });
1232
+ exports.machineSaltFilePath = machineSaltFilePath;
1233
+ exports.readOrCreateMachineSalt = readOrCreateMachineSalt;
1234
+ exports.hashWithMachineSalt = hashWithMachineSalt;
1235
+ var crypto = __importStar(__require("crypto"));
1236
+ var fs = __importStar(__require("fs"));
1237
+ var os = __importStar(__require("os"));
1238
+ var path = __importStar(__require("path"));
1239
+ function machineSaltFilePath() {
1240
+ return path.join(os.homedir(), ".ascenda", "salt");
1241
+ }
1242
+ var cache = /* @__PURE__ */ new Map();
1243
+ function readOrCreateMachineSalt(saltFilePath = machineSaltFilePath()) {
1244
+ const hit = cache.get(saltFilePath);
1245
+ if (hit)
1246
+ return hit;
1247
+ const dir = path.dirname(saltFilePath);
1248
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
1249
+ let salt;
1250
+ try {
1251
+ salt = crypto.randomBytes(32).toString("hex");
1252
+ fs.writeFileSync(saltFilePath, salt, { encoding: "utf8", mode: 384, flag: "wx" });
1253
+ } catch (error) {
1254
+ if (error.code !== "EEXIST")
1255
+ throw error;
1256
+ salt = fs.readFileSync(saltFilePath, "utf8").trim();
1257
+ }
1258
+ if (process.platform !== "win32") {
1259
+ fs.chmodSync(dir, 448);
1260
+ fs.chmodSync(saltFilePath, 384);
1261
+ }
1262
+ cache.set(saltFilePath, salt);
1263
+ return salt;
1264
+ }
1265
+ function hashWithMachineSalt(value, saltFilePath) {
1266
+ if (!value)
1267
+ return null;
1268
+ return crypto.createHash("sha256").update(readOrCreateMachineSalt(saltFilePath)).update("\0").update(value).digest("hex").slice(0, 16);
1269
+ }
1270
+ }
1271
+ });
1272
+
1273
+ // ../packages/tool-kit/out/workContext.js
1274
+ var require_workContext = __commonJS({
1275
+ "../packages/tool-kit/out/workContext.js"(exports) {
1276
+ "use strict";
1277
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1278
+ if (k2 === void 0) k2 = k;
1279
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1280
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1281
+ desc = { enumerable: true, get: function() {
1282
+ return m[k];
1283
+ } };
1284
+ }
1285
+ Object.defineProperty(o, k2, desc);
1286
+ } : function(o, m, k, k2) {
1287
+ if (k2 === void 0) k2 = k;
1288
+ o[k2] = m[k];
1289
+ });
1290
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1291
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1292
+ } : function(o, v) {
1293
+ o["default"] = v;
1294
+ });
1295
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1296
+ var ownKeys = function(o) {
1297
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
1298
+ var ar = [];
1299
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1300
+ return ar;
1301
+ };
1302
+ return ownKeys(o);
1303
+ };
1304
+ return function(mod) {
1305
+ if (mod && mod.__esModule) return mod;
1306
+ var result = {};
1307
+ if (mod != null) {
1308
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1309
+ }
1310
+ __setModuleDefault(result, mod);
1311
+ return result;
1312
+ };
1313
+ }();
1314
+ Object.defineProperty(exports, "__esModule", { value: true });
1315
+ exports.deriveWorkContext = deriveWorkContext;
1316
+ var fs = __importStar(__require("fs"));
1317
+ var path = __importStar(__require("path"));
1318
+ var salt_1 = require_salt();
1319
+ var MAX_WALK_DEPTH = 64;
1320
+ function deriveWorkContext(cwd, saltFilePath) {
1321
+ if (!cwd || !cwd.trim())
1322
+ return null;
1323
+ const startPath = stripTrailingSeparators(cwd.trim());
1324
+ let roots = null;
1325
+ try {
1326
+ roots = resolveRepositoryRoots(startPath);
1327
+ } catch {
1328
+ roots = null;
1329
+ }
1330
+ const workspacePath = roots?.checkoutRoot ?? startPath;
1331
+ const workspaceLabel = basenameOf(workspacePath);
1332
+ if (!workspaceLabel)
1333
+ return null;
1334
+ const projectPath = roots?.canonicalRoot ?? null;
1335
+ const projectLabel = (projectPath ? basenameOf(projectPath) : null) ?? workspaceLabel;
1336
+ return {
1337
+ workspaceLabel,
1338
+ projectLabel,
1339
+ workspaceHash: (0, salt_1.hashWithMachineSalt)(workspaceLabel, saltFilePath),
1340
+ projectHash: (0, salt_1.hashWithMachineSalt)(projectLabel, saltFilePath),
1341
+ workspacePath,
1342
+ projectPath
1343
+ };
1344
+ }
1345
+ function resolveRepositoryRoots(startDir) {
1346
+ if (!fs.existsSync(startDir))
1347
+ return null;
1348
+ let dir = startDir;
1349
+ for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
1350
+ const dotGit = path.join(dir, ".git");
1351
+ let stat = null;
1352
+ try {
1353
+ stat = fs.statSync(dotGit);
1354
+ } catch {
1355
+ stat = null;
1356
+ }
1357
+ if (stat?.isDirectory())
1358
+ return { checkoutRoot: dir, canonicalRoot: dir };
1359
+ if (stat?.isFile())
1360
+ return { checkoutRoot: dir, canonicalRoot: worktreeParentRoot(dotGit, dir) ?? dir };
1361
+ const parent = path.dirname(dir);
1362
+ if (parent === dir)
1363
+ return null;
1364
+ dir = parent;
1365
+ }
1366
+ return null;
1367
+ }
1368
+ function worktreeParentRoot(dotGitFile, containingDir) {
1369
+ let gitdir;
1370
+ try {
1371
+ const match = /^gitdir:\s*(.+)\s*$/m.exec(fs.readFileSync(dotGitFile, "utf8"));
1372
+ if (!match)
1373
+ return null;
1374
+ gitdir = match[1].trim();
1375
+ } catch {
1376
+ return null;
1377
+ }
1378
+ const resolved = path.resolve(containingDir, gitdir);
1379
+ const marker = `${path.sep}.git${path.sep}worktrees${path.sep}`;
1380
+ const idx = resolved.indexOf(marker);
1381
+ if (idx === -1)
1382
+ return null;
1383
+ return resolved.slice(0, idx);
1384
+ }
1385
+ function stripTrailingSeparators(value) {
1386
+ let end = value.length;
1387
+ while (end > 1 && (value[end - 1] === "/" || value[end - 1] === "\\"))
1388
+ end--;
1389
+ return value.slice(0, end);
1390
+ }
1391
+ function basenameOf(value) {
1392
+ const segment = value.split(/[\\/]/).filter(Boolean).pop() ?? null;
1393
+ return segment && segment.length > 0 ? segment : null;
1394
+ }
1395
+ }
1396
+ });
1397
+
1010
1398
  // ../packages/tool-kit/out/hookAdapter.js
1011
1399
  var require_hookAdapter = __commonJS({
1012
1400
  "../packages/tool-kit/out/hookAdapter.js"(exports) {
1013
1401
  "use strict";
1014
1402
  Object.defineProperty(exports, "__esModule", { value: true });
1015
1403
  exports.DEFAULT_API_BASE_URL = void 0;
1404
+ exports.resolveContextHashes = resolveContextHashes;
1016
1405
  exports.loadCliAgentConfig = loadCliAgentConfig;
1017
1406
  exports.deliverHookEvents = deliverHookEvents;
1407
+ var contextRegistry_1 = require_contextRegistry();
1018
1408
  var eventLog_1 = require_eventLog();
1019
1409
  var eventSender_1 = require_eventSender();
1020
1410
  var tokenStore_1 = require_tokenStore();
1411
+ var workContext_1 = require_workContext();
1021
1412
  exports.DEFAULT_API_BASE_URL = "https://api.ascenda.one";
1022
- function loadCliAgentConfig(toolType, sessionIdFromHook) {
1413
+ function resolveContextHashes(cwd) {
1414
+ const workspaceOverride = process.env.ASCENDA_WORKSPACE_HASH?.trim() || null;
1415
+ const projectOverride = process.env.ASCENDA_PROJECT_HASH?.trim() || null;
1416
+ if (workspaceOverride && projectOverride)
1417
+ return { workspaceHash: workspaceOverride, projectHash: projectOverride };
1418
+ const context = (0, workContext_1.deriveWorkContext)(cwd ?? process.cwd());
1419
+ if (context)
1420
+ (0, contextRegistry_1.recordWorkContext)(context);
1421
+ return {
1422
+ workspaceHash: workspaceOverride ?? context?.workspaceHash ?? null,
1423
+ projectHash: projectOverride ?? context?.projectHash ?? null
1424
+ };
1425
+ }
1426
+ function loadCliAgentConfig(toolType, sessionIdFromHook, cwd) {
1023
1427
  const apiBaseUrl = (process.env.ASCENDA_API_BASE_URL ?? exports.DEFAULT_API_BASE_URL).replace(/\/$/, "");
1024
1428
  const toolInstallationIdRaw = process.env.ASCENDA_TOOL_INSTALLATION_ID;
1025
1429
  if (!toolInstallationIdRaw)
@@ -1032,13 +1436,15 @@ var require_hookAdapter = __commonJS({
1032
1436
  throw new Error("Missing ASCENDA_EVENT_WRITE_TOKEN (or token file)");
1033
1437
  if (!fileToken)
1034
1438
  (0, tokenStore_1.persistEventWriteToken)(tokenFilePath, eventWriteToken);
1439
+ const contextHashes = resolveContextHashes(cwd);
1035
1440
  return {
1036
1441
  apiBaseUrl,
1037
1442
  toolInstallationId,
1038
1443
  eventWriteToken,
1039
1444
  tokenFilePath,
1040
1445
  sessionId: process.env.ASCENDA_SESSION_ID ?? sessionIdFromHook ?? null,
1041
- workspaceHash: process.env.ASCENDA_WORKSPACE_HASH ?? null,
1446
+ workspaceHash: contextHashes.workspaceHash,
1447
+ projectHash: contextHashes.projectHash,
1042
1448
  // Agents await command hooks; fail fast rather than stall the user's turn.
1043
1449
  timeoutMs: parsePositiveInt(process.env.ASCENDA_HTTP_TIMEOUT_MS) ?? 3e3
1044
1450
  };
@@ -1049,11 +1455,12 @@ var require_hookAdapter = __commonJS({
1049
1455
  const notice = options.onNotice ?? ((message) => console.error(message));
1050
1456
  let config;
1051
1457
  try {
1052
- config = loadCliAgentConfig(options.toolType, options.sessionId);
1458
+ config = loadCliAgentConfig(options.toolType, options.sessionId, options.cwd);
1053
1459
  } catch (error) {
1054
1460
  const logFile = (0, eventLog_1.resolveEventLogPath)();
1055
1461
  if (!logFile)
1056
1462
  throw error;
1463
+ const contextHashes = resolveContextHashes(options.cwd);
1057
1464
  for (const event of events) {
1058
1465
  (0, eventLog_1.appendEventLog)(logFile, {
1059
1466
  loggedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1062,7 +1469,8 @@ var require_hookAdapter = __commonJS({
1062
1469
  toolInstallationId: `${options.toolType}:unpaired`,
1063
1470
  source: options.source,
1064
1471
  sessionId: options.sessionId ?? null,
1065
- workspaceHash: process.env.ASCENDA_WORKSPACE_HASH ?? null
1472
+ workspaceHash: contextHashes.workspaceHash,
1473
+ projectHash: contextHashes.projectHash
1066
1474
  }, event)
1067
1475
  });
1068
1476
  }
@@ -1076,6 +1484,7 @@ var require_hookAdapter = __commonJS({
1076
1484
  tokenFilePath: config.tokenFilePath,
1077
1485
  sessionId: config.sessionId,
1078
1486
  workspaceHash: config.workspaceHash,
1487
+ projectHash: config.projectHash,
1079
1488
  timeoutMs: config.timeoutMs
1080
1489
  });
1081
1490
  for (const event of events) {
@@ -1181,89 +1590,6 @@ var require_turnState = __commonJS({
1181
1590
  }
1182
1591
  });
1183
1592
 
1184
- // ../packages/tool-kit/out/salt.js
1185
- var require_salt = __commonJS({
1186
- "../packages/tool-kit/out/salt.js"(exports) {
1187
- "use strict";
1188
- var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1189
- if (k2 === void 0) k2 = k;
1190
- var desc = Object.getOwnPropertyDescriptor(m, k);
1191
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1192
- desc = { enumerable: true, get: function() {
1193
- return m[k];
1194
- } };
1195
- }
1196
- Object.defineProperty(o, k2, desc);
1197
- } : function(o, m, k, k2) {
1198
- if (k2 === void 0) k2 = k;
1199
- o[k2] = m[k];
1200
- });
1201
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1202
- Object.defineProperty(o, "default", { enumerable: true, value: v });
1203
- } : function(o, v) {
1204
- o["default"] = v;
1205
- });
1206
- var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1207
- var ownKeys = function(o) {
1208
- ownKeys = Object.getOwnPropertyNames || function(o2) {
1209
- var ar = [];
1210
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1211
- return ar;
1212
- };
1213
- return ownKeys(o);
1214
- };
1215
- return function(mod) {
1216
- if (mod && mod.__esModule) return mod;
1217
- var result = {};
1218
- if (mod != null) {
1219
- for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1220
- }
1221
- __setModuleDefault(result, mod);
1222
- return result;
1223
- };
1224
- }();
1225
- Object.defineProperty(exports, "__esModule", { value: true });
1226
- exports.machineSaltFilePath = machineSaltFilePath;
1227
- exports.readOrCreateMachineSalt = readOrCreateMachineSalt;
1228
- exports.hashWithMachineSalt = hashWithMachineSalt;
1229
- var crypto = __importStar(__require("crypto"));
1230
- var fs = __importStar(__require("fs"));
1231
- var os = __importStar(__require("os"));
1232
- var path = __importStar(__require("path"));
1233
- function machineSaltFilePath() {
1234
- return path.join(os.homedir(), ".ascenda", "salt");
1235
- }
1236
- var cache = /* @__PURE__ */ new Map();
1237
- function readOrCreateMachineSalt(saltFilePath = machineSaltFilePath()) {
1238
- const hit = cache.get(saltFilePath);
1239
- if (hit)
1240
- return hit;
1241
- const dir = path.dirname(saltFilePath);
1242
- fs.mkdirSync(dir, { recursive: true, mode: 448 });
1243
- let salt;
1244
- try {
1245
- salt = crypto.randomBytes(32).toString("hex");
1246
- fs.writeFileSync(saltFilePath, salt, { encoding: "utf8", mode: 384, flag: "wx" });
1247
- } catch (error) {
1248
- if (error.code !== "EEXIST")
1249
- throw error;
1250
- salt = fs.readFileSync(saltFilePath, "utf8").trim();
1251
- }
1252
- if (process.platform !== "win32") {
1253
- fs.chmodSync(dir, 448);
1254
- fs.chmodSync(saltFilePath, 384);
1255
- }
1256
- cache.set(saltFilePath, salt);
1257
- return salt;
1258
- }
1259
- function hashWithMachineSalt(value, saltFilePath) {
1260
- if (!value)
1261
- return null;
1262
- return crypto.createHash("sha256").update(readOrCreateMachineSalt(saltFilePath)).update("\0").update(value).digest("hex").slice(0, 16);
1263
- }
1264
- }
1265
- });
1266
-
1267
1593
  // ../packages/tool-kit/out/liveBus.js
1268
1594
  var require_liveBus = __commonJS({
1269
1595
  "../packages/tool-kit/out/liveBus.js"(exports) {
@@ -1395,8 +1721,8 @@ var require_out2 = __commonJS({
1395
1721
  "../packages/tool-kit/out/index.js"(exports) {
1396
1722
  "use strict";
1397
1723
  Object.defineProperty(exports, "__esModule", { value: true });
1398
- exports.postToolEventsBatch = exports.postToolEvent = exports.renewToolToken = exports.getPairingStatus = exports.createPairingSession = exports.AscendaApiError = exports.liveBusSocketCandidates = exports.liveBusSocketPath = exports.bucketPromptSize = exports.emitLiveSignal = exports.hashWithMachineSalt = exports.readOrCreateMachineSalt = exports.machineSaltFilePath = exports.markFailureNotified = exports.shouldAnnounceFailure = exports.recordSendOutcome = exports.readCollectorState = exports.defaultStateFilePath = exports.readTokenFile = exports.persistEventWriteToken = exports.defaultTokenFilePath = exports.recordTurnStart = exports.consumeTurnDurationMs = exports.loadCliAgentConfig = exports.deliverHookEvents = exports.DEFAULT_API_BASE_URL = exports.resolveEventLogPath = exports.expandUserPath = exports.appendEventLog = exports.EVENT_LOG_ENV_VAR = exports.buildEventPayload = exports.AscendaSemanticEventError = exports.AscendaEventSender = exports.looksLikeCorrection = exports.outcomeForHook = exports.inferOutcome = exports.getNestedNumber = exports.getNestedString = exports.getNested = exports.getNumber = exports.getString = exports.isAfterHours = exports.bucketDurationMs = exports.bucketLinesChanged = exports.invitesDebrief = exports.classifyWorkMilestone = exports.isReworkGitAction = exports.classifyGitAction = exports.isVerificationCommand = exports.classifyCommand = void 0;
1399
- exports.isRetryableStatus = exports.parseIngestResponse = void 0;
1724
+ exports.workContextRegistryFilePath = exports.readWorkContextRegistry = exports.recordWorkContextAlias = exports.recordWorkContext = exports.deriveWorkContext = exports.hashWithMachineSalt = exports.readOrCreateMachineSalt = exports.machineSaltFilePath = exports.markFailureNotified = exports.shouldAnnounceFailure = exports.recordSendOutcome = exports.readCollectorState = exports.defaultStateFilePath = exports.readTokenFile = exports.persistEventWriteToken = exports.defaultTokenFilePath = exports.recordTurnStart = exports.consumeTurnDurationMs = exports.resolveContextHashes = exports.loadCliAgentConfig = exports.deliverHookEvents = exports.DEFAULT_API_BASE_URL = exports.resolveEventLogPath = exports.expandUserPath = exports.appendEventLog = exports.EVENT_LOG_ENV_VAR = exports.buildEventPayload = exports.AscendaSemanticEventError = exports.AscendaEventSender = 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.invitesDebrief = exports.classifyWorkMilestone = exports.isReworkGitAction = exports.classifyGitAction = exports.isVerificationCommand = exports.classifyCommand = void 0;
1725
+ exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = exports.postToolEvent = exports.renewToolToken = exports.getPairingStatus = exports.createPairingSession = exports.AscendaApiError = exports.liveBusSocketCandidates = exports.liveBusSocketPath = exports.bucketPromptSize = exports.emitLiveSignal = void 0;
1400
1726
  var commandClassifier_1 = require_commandClassifier();
1401
1727
  Object.defineProperty(exports, "classifyCommand", { enumerable: true, get: function() {
1402
1728
  return commandClassifier_1.classifyCommand;
@@ -1429,6 +1755,18 @@ var require_out2 = __commonJS({
1429
1755
  Object.defineProperty(exports, "isAfterHours", { enumerable: true, get: function() {
1430
1756
  return afterHours_1.isAfterHours;
1431
1757
  } });
1758
+ Object.defineProperty(exports, "isOutsideBusinessHours", { enumerable: true, get: function() {
1759
+ return afterHours_1.isOutsideBusinessHours;
1760
+ } });
1761
+ Object.defineProperty(exports, "BUSINESS_DAY", { enumerable: true, get: function() {
1762
+ return afterHours_1.BUSINESS_DAY;
1763
+ } });
1764
+ Object.defineProperty(exports, "utcOffsetMinutesAt", { enumerable: true, get: function() {
1765
+ return afterHours_1.utcOffsetMinutesAt;
1766
+ } });
1767
+ Object.defineProperty(exports, "localHourAt", { enumerable: true, get: function() {
1768
+ return afterHours_1.localHourAt;
1769
+ } });
1432
1770
  var payload_1 = require_payload();
1433
1771
  Object.defineProperty(exports, "getString", { enumerable: true, get: function() {
1434
1772
  return payload_1.getString;
@@ -1487,6 +1825,9 @@ var require_out2 = __commonJS({
1487
1825
  Object.defineProperty(exports, "loadCliAgentConfig", { enumerable: true, get: function() {
1488
1826
  return hookAdapter_1.loadCliAgentConfig;
1489
1827
  } });
1828
+ Object.defineProperty(exports, "resolveContextHashes", { enumerable: true, get: function() {
1829
+ return hookAdapter_1.resolveContextHashes;
1830
+ } });
1490
1831
  var turnState_1 = require_turnState();
1491
1832
  Object.defineProperty(exports, "consumeTurnDurationMs", { enumerable: true, get: function() {
1492
1833
  return turnState_1.consumeTurnDurationMs;
@@ -1530,6 +1871,23 @@ var require_out2 = __commonJS({
1530
1871
  Object.defineProperty(exports, "hashWithMachineSalt", { enumerable: true, get: function() {
1531
1872
  return salt_1.hashWithMachineSalt;
1532
1873
  } });
1874
+ var workContext_1 = require_workContext();
1875
+ Object.defineProperty(exports, "deriveWorkContext", { enumerable: true, get: function() {
1876
+ return workContext_1.deriveWorkContext;
1877
+ } });
1878
+ var contextRegistry_1 = require_contextRegistry();
1879
+ Object.defineProperty(exports, "recordWorkContext", { enumerable: true, get: function() {
1880
+ return contextRegistry_1.recordWorkContext;
1881
+ } });
1882
+ Object.defineProperty(exports, "recordWorkContextAlias", { enumerable: true, get: function() {
1883
+ return contextRegistry_1.recordWorkContextAlias;
1884
+ } });
1885
+ Object.defineProperty(exports, "readWorkContextRegistry", { enumerable: true, get: function() {
1886
+ return contextRegistry_1.readWorkContextRegistry;
1887
+ } });
1888
+ Object.defineProperty(exports, "workContextRegistryFilePath", { enumerable: true, get: function() {
1889
+ return contextRegistry_1.workContextRegistryFilePath;
1890
+ } });
1533
1891
  var liveBus_1 = require_liveBus();
1534
1892
  Object.defineProperty(exports, "emitLiveSignal", { enumerable: true, get: function() {
1535
1893
  return liveBus_1.emitLiveSignal;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "publishConfig": { "access": "public" },
3
3
  "name": "@ascenda-one/github-collector",
4
- "version": "0.1.11",
4
+ "version": "0.1.13",
5
5
  "description": "Code-forge collaboration collector for Ascenda work telemetry — first-person review and pull-request signals.",
6
6
  "repository": {
7
7
  "type": "git",