@ascenda-one/agent-mcp 0.1.12 → 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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +427 -89
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -23,7 +23,7 @@ Agent (Claude Code / Cursor / other MCP host)
23
23
  -> AscendaEventSender.sendSemanticSignal (@ascenda-one/tool-kit)
24
24
  -> Ascenda backend (POST /v1/tool-events, consentScope: semantic_work_signals)
25
25
  -> paired anonymous Ascenda user
26
- -> Weekly Loop trigger evaluation / work-map (asc-core-be)
26
+ -> Weekly Loop trigger evaluation / work-map (backend)
27
27
  ```
28
28
 
29
29
  Reuses the same pairing model as the hooks and IDE extensions — same `toolInstallationId` + `eventWriteToken`, same token file convention — but **does not mint its own tool type**. See `src/config.ts`: this process is host-agnostic (the same binary runs under Claude Code or Cursor), so it refuses to guess a prefix the way `ascenda-claude-hook`/`ascenda-codex-hook` do. Passing an id that already contains `:` (i.e. the exact value your existing pairing shows) reuses that pairing's token file; a bare id is rejected rather than silently minting a second, unpaired tool identity.
package/dist/cli.js CHANGED
@@ -246,9 +246,28 @@ var require_afterHours = __commonJS({
246
246
  "../packages/tool-kit/out/afterHours.js"(exports) {
247
247
  "use strict";
248
248
  Object.defineProperty(exports, "__esModule", { value: true });
249
+ exports.BUSINESS_DAY = void 0;
250
+ exports.isOutsideBusinessHours = isOutsideBusinessHours;
249
251
  exports.isAfterHours = isAfterHours;
250
252
  exports.utcOffsetMinutesAt = utcOffsetMinutesAt;
251
253
  exports.localHourAt = localHourAt;
254
+ exports.BUSINESS_DAY = {
255
+ /** 0 = Sunday … 6 = Saturday. */
256
+ days: [1, 2, 3, 4, 5],
257
+ start: "09:00",
258
+ end: "17:00"
259
+ };
260
+ function isOutsideBusinessHours(at = /* @__PURE__ */ new Date(), opts = {}) {
261
+ const days = opts.days ?? exports.BUSINESS_DAY.days;
262
+ if (!days.includes(at.getDay()))
263
+ return true;
264
+ const minutes = at.getHours() * 60 + at.getMinutes();
265
+ const start = parseTimeToMinutes(opts.start ?? exports.BUSINESS_DAY.start, 9 * 60);
266
+ const end = parseTimeToMinutes(opts.end ?? exports.BUSINESS_DAY.end, 17 * 60);
267
+ if (start >= end)
268
+ return false;
269
+ return minutes < start || minutes >= end;
270
+ }
252
271
  function isAfterHours(now = /* @__PURE__ */ new Date(), start = "19:00", end = "07:00") {
253
272
  const currentMinutes = now.getHours() * 60 + now.getMinutes();
254
273
  const startMinutes = parseTimeToMinutes(start, 19 * 60);
@@ -851,6 +870,7 @@ var require_eventSender = __commonJS({
851
870
  utcOffsetMinutes: (0, afterHours_1.utcOffsetMinutesAt)(/* @__PURE__ */ new Date()),
852
871
  sessionId: identity.sessionId ?? void 0,
853
872
  workspaceHash: identity.workspaceHash ?? void 0,
873
+ projectHash: identity.projectHash ?? void 0,
854
874
  consentScope: tool_contract_1.ASCENDA_CONSENT_SCOPE,
855
875
  provenance: tool_contract_1.ASCENDA_PROVENANCE,
856
876
  privacyMode: "metadata_only",
@@ -906,6 +926,7 @@ var require_eventSender = __commonJS({
906
926
  severity: "low",
907
927
  sessionId: this.config.sessionId ?? void 0,
908
928
  workspaceHash: this.config.workspaceHash ?? void 0,
929
+ projectHash: this.config.projectHash ?? void 0,
909
930
  consentScope: tool_contract_1.ASCENDA_SEMANTIC_CONSENT_SCOPE,
910
931
  provenance: tool_contract_1.ASCENDA_SEMANTIC_PROVENANCE,
911
932
  privacyMode: "metadata_only",
@@ -935,6 +956,7 @@ var require_eventSender = __commonJS({
935
956
  severity: "low",
936
957
  sessionId: this.config.sessionId ?? void 0,
937
958
  workspaceHash: this.config.workspaceHash ?? void 0,
959
+ projectHash: this.config.projectHash ?? void 0,
938
960
  consentScope: tool_contract_1.ASCENDA_COLLABORATION_CONSENT_SCOPE,
939
961
  provenance: tool_contract_1.ASCENDA_PROVENANCE,
940
962
  privacyMode: "metadata_only",
@@ -1025,19 +1047,387 @@ var require_eventSender = __commonJS({
1025
1047
  }
1026
1048
  });
1027
1049
 
1050
+ // ../packages/tool-kit/out/contextRegistry.js
1051
+ var require_contextRegistry = __commonJS({
1052
+ "../packages/tool-kit/out/contextRegistry.js"(exports) {
1053
+ "use strict";
1054
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1055
+ if (k2 === void 0) k2 = k;
1056
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1057
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1058
+ desc = { enumerable: true, get: function() {
1059
+ return m[k];
1060
+ } };
1061
+ }
1062
+ Object.defineProperty(o, k2, desc);
1063
+ } : function(o, m, k, k2) {
1064
+ if (k2 === void 0) k2 = k;
1065
+ o[k2] = m[k];
1066
+ });
1067
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1068
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1069
+ } : function(o, v) {
1070
+ o["default"] = v;
1071
+ });
1072
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1073
+ var ownKeys = function(o) {
1074
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
1075
+ var ar = [];
1076
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1077
+ return ar;
1078
+ };
1079
+ return ownKeys(o);
1080
+ };
1081
+ return function(mod) {
1082
+ if (mod && mod.__esModule) return mod;
1083
+ var result = {};
1084
+ if (mod != null) {
1085
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1086
+ }
1087
+ __setModuleDefault(result, mod);
1088
+ return result;
1089
+ };
1090
+ }();
1091
+ Object.defineProperty(exports, "__esModule", { value: true });
1092
+ exports.workContextRegistryFilePath = workContextRegistryFilePath;
1093
+ exports.readWorkContextRegistry = readWorkContextRegistry;
1094
+ exports.recordWorkContext = recordWorkContext;
1095
+ exports.recordWorkContextAlias = recordWorkContextAlias;
1096
+ var fs = __importStar(__require("fs"));
1097
+ var os = __importStar(__require("os"));
1098
+ var path = __importStar(__require("path"));
1099
+ var MAX_PATHS_PER_ENTRY = 8;
1100
+ function workContextRegistryFilePath() {
1101
+ return path.join(os.homedir(), ".ascenda", "work-contexts.json");
1102
+ }
1103
+ function readWorkContextRegistry(registryFilePath = workContextRegistryFilePath()) {
1104
+ try {
1105
+ const parsed = JSON.parse(fs.readFileSync(registryFilePath, "utf8"));
1106
+ if (parsed && parsed.version === 1 && parsed.contexts && typeof parsed.contexts === "object") {
1107
+ return parsed;
1108
+ }
1109
+ } catch {
1110
+ }
1111
+ return { version: 1, contexts: {} };
1112
+ }
1113
+ function recordWorkContext(context, options) {
1114
+ if (!context)
1115
+ return false;
1116
+ const updates = [];
1117
+ if (context.projectHash && context.projectLabel) {
1118
+ updates.push({ hash: context.projectHash, kind: "project", label: context.projectLabel, observedPath: context.projectPath ?? context.workspacePath });
1119
+ }
1120
+ if (context.workspaceHash && context.workspaceLabel && context.workspaceHash !== context.projectHash) {
1121
+ updates.push({ hash: context.workspaceHash, kind: "workspace", label: context.workspaceLabel, observedPath: context.workspacePath });
1122
+ }
1123
+ return upsert(updates, options);
1124
+ }
1125
+ function recordWorkContextAlias(hash, label, observedPath, options) {
1126
+ if (!hash || !label)
1127
+ return false;
1128
+ return upsert([{ hash, kind: "alias", label, observedPath: observedPath ?? null }], options);
1129
+ }
1130
+ function upsert(updates, options) {
1131
+ if (updates.length === 0)
1132
+ return false;
1133
+ try {
1134
+ const registryFilePath = options?.registryFilePath ?? workContextRegistryFilePath();
1135
+ const nowIso = (options?.now ?? /* @__PURE__ */ new Date()).toISOString();
1136
+ const registry2 = readWorkContextRegistry(registryFilePath);
1137
+ let dirty = false;
1138
+ for (const update of updates) {
1139
+ const existing = registry2.contexts[update.hash];
1140
+ if (!existing) {
1141
+ registry2.contexts[update.hash] = {
1142
+ kind: update.kind,
1143
+ label: update.label,
1144
+ paths: update.observedPath ? [update.observedPath] : [],
1145
+ firstSeenAt: nowIso,
1146
+ lastSeenAt: nowIso
1147
+ };
1148
+ dirty = true;
1149
+ continue;
1150
+ }
1151
+ if (existing.kind === "alias" && update.kind !== "alias") {
1152
+ existing.kind = update.kind;
1153
+ dirty = true;
1154
+ }
1155
+ if (existing.label !== update.label && update.kind !== "alias") {
1156
+ existing.label = update.label;
1157
+ dirty = true;
1158
+ }
1159
+ if (update.observedPath && !existing.paths.includes(update.observedPath)) {
1160
+ if (existing.paths.length < MAX_PATHS_PER_ENTRY)
1161
+ existing.paths.push(update.observedPath);
1162
+ dirty = true;
1163
+ }
1164
+ if (dayOf(existing.lastSeenAt) !== dayOf(nowIso)) {
1165
+ existing.lastSeenAt = nowIso;
1166
+ dirty = true;
1167
+ }
1168
+ }
1169
+ if (!dirty)
1170
+ return false;
1171
+ writeRegistry(registryFilePath, registry2);
1172
+ return true;
1173
+ } catch {
1174
+ return false;
1175
+ }
1176
+ }
1177
+ function dayOf(iso) {
1178
+ return iso.slice(0, 10);
1179
+ }
1180
+ function writeRegistry(registryFilePath, registry2) {
1181
+ const dir = path.dirname(registryFilePath);
1182
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
1183
+ const tmp = `${registryFilePath}.${process.pid}.tmp`;
1184
+ fs.writeFileSync(tmp, `${JSON.stringify(registry2, null, 2)}
1185
+ `, { encoding: "utf8", mode: 384 });
1186
+ fs.renameSync(tmp, registryFilePath);
1187
+ if (process.platform !== "win32") {
1188
+ fs.chmodSync(registryFilePath, 384);
1189
+ }
1190
+ }
1191
+ }
1192
+ });
1193
+
1194
+ // ../packages/tool-kit/out/salt.js
1195
+ var require_salt = __commonJS({
1196
+ "../packages/tool-kit/out/salt.js"(exports) {
1197
+ "use strict";
1198
+ var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1199
+ if (k2 === void 0) k2 = k;
1200
+ var desc = Object.getOwnPropertyDescriptor(m, k);
1201
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1202
+ desc = { enumerable: true, get: function() {
1203
+ return m[k];
1204
+ } };
1205
+ }
1206
+ Object.defineProperty(o, k2, desc);
1207
+ } : function(o, m, k, k2) {
1208
+ if (k2 === void 0) k2 = k;
1209
+ o[k2] = m[k];
1210
+ });
1211
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1212
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
1213
+ } : function(o, v) {
1214
+ o["default"] = v;
1215
+ });
1216
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1217
+ var ownKeys = function(o) {
1218
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
1219
+ var ar = [];
1220
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1221
+ return ar;
1222
+ };
1223
+ return ownKeys(o);
1224
+ };
1225
+ return function(mod) {
1226
+ if (mod && mod.__esModule) return mod;
1227
+ var result = {};
1228
+ if (mod != null) {
1229
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1230
+ }
1231
+ __setModuleDefault(result, mod);
1232
+ return result;
1233
+ };
1234
+ }();
1235
+ Object.defineProperty(exports, "__esModule", { value: true });
1236
+ exports.machineSaltFilePath = machineSaltFilePath;
1237
+ exports.readOrCreateMachineSalt = readOrCreateMachineSalt;
1238
+ exports.hashWithMachineSalt = hashWithMachineSalt;
1239
+ var crypto = __importStar(__require("crypto"));
1240
+ var fs = __importStar(__require("fs"));
1241
+ var os = __importStar(__require("os"));
1242
+ var path = __importStar(__require("path"));
1243
+ function machineSaltFilePath() {
1244
+ return path.join(os.homedir(), ".ascenda", "salt");
1245
+ }
1246
+ var cache = /* @__PURE__ */ new Map();
1247
+ function readOrCreateMachineSalt(saltFilePath = machineSaltFilePath()) {
1248
+ const hit = cache.get(saltFilePath);
1249
+ if (hit)
1250
+ return hit;
1251
+ const dir = path.dirname(saltFilePath);
1252
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
1253
+ let salt;
1254
+ try {
1255
+ salt = crypto.randomBytes(32).toString("hex");
1256
+ fs.writeFileSync(saltFilePath, salt, { encoding: "utf8", mode: 384, flag: "wx" });
1257
+ } catch (error2) {
1258
+ if (error2.code !== "EEXIST")
1259
+ throw error2;
1260
+ salt = fs.readFileSync(saltFilePath, "utf8").trim();
1261
+ }
1262
+ if (process.platform !== "win32") {
1263
+ fs.chmodSync(dir, 448);
1264
+ fs.chmodSync(saltFilePath, 384);
1265
+ }
1266
+ cache.set(saltFilePath, salt);
1267
+ return salt;
1268
+ }
1269
+ function hashWithMachineSalt(value, saltFilePath) {
1270
+ if (!value)
1271
+ return null;
1272
+ return crypto.createHash("sha256").update(readOrCreateMachineSalt(saltFilePath)).update("\0").update(value).digest("hex").slice(0, 16);
1273
+ }
1274
+ }
1275
+ });
1276
+
1277
+ // ../packages/tool-kit/out/workContext.js
1278
+ var require_workContext = __commonJS({
1279
+ "../packages/tool-kit/out/workContext.js"(exports) {
1280
+ "use strict";
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.deriveWorkContext = deriveWorkContext;
1320
+ var fs = __importStar(__require("fs"));
1321
+ var path = __importStar(__require("path"));
1322
+ var salt_1 = require_salt();
1323
+ var MAX_WALK_DEPTH = 64;
1324
+ function deriveWorkContext(cwd, saltFilePath) {
1325
+ if (!cwd || !cwd.trim())
1326
+ return null;
1327
+ const startPath = stripTrailingSeparators(cwd.trim());
1328
+ let roots = null;
1329
+ try {
1330
+ roots = resolveRepositoryRoots(startPath);
1331
+ } catch {
1332
+ roots = null;
1333
+ }
1334
+ const workspacePath = roots?.checkoutRoot ?? startPath;
1335
+ const workspaceLabel = basenameOf(workspacePath);
1336
+ if (!workspaceLabel)
1337
+ return null;
1338
+ const projectPath = roots?.canonicalRoot ?? null;
1339
+ const projectLabel = (projectPath ? basenameOf(projectPath) : null) ?? workspaceLabel;
1340
+ return {
1341
+ workspaceLabel,
1342
+ projectLabel,
1343
+ workspaceHash: (0, salt_1.hashWithMachineSalt)(workspaceLabel, saltFilePath),
1344
+ projectHash: (0, salt_1.hashWithMachineSalt)(projectLabel, saltFilePath),
1345
+ workspacePath,
1346
+ projectPath
1347
+ };
1348
+ }
1349
+ function resolveRepositoryRoots(startDir) {
1350
+ if (!fs.existsSync(startDir))
1351
+ return null;
1352
+ let dir = startDir;
1353
+ for (let depth = 0; depth < MAX_WALK_DEPTH; depth++) {
1354
+ const dotGit = path.join(dir, ".git");
1355
+ let stat = null;
1356
+ try {
1357
+ stat = fs.statSync(dotGit);
1358
+ } catch {
1359
+ stat = null;
1360
+ }
1361
+ if (stat?.isDirectory())
1362
+ return { checkoutRoot: dir, canonicalRoot: dir };
1363
+ if (stat?.isFile())
1364
+ return { checkoutRoot: dir, canonicalRoot: worktreeParentRoot(dotGit, dir) ?? dir };
1365
+ const parent = path.dirname(dir);
1366
+ if (parent === dir)
1367
+ return null;
1368
+ dir = parent;
1369
+ }
1370
+ return null;
1371
+ }
1372
+ function worktreeParentRoot(dotGitFile, containingDir) {
1373
+ let gitdir;
1374
+ try {
1375
+ const match = /^gitdir:\s*(.+)\s*$/m.exec(fs.readFileSync(dotGitFile, "utf8"));
1376
+ if (!match)
1377
+ return null;
1378
+ gitdir = match[1].trim();
1379
+ } catch {
1380
+ return null;
1381
+ }
1382
+ const resolved = path.resolve(containingDir, gitdir);
1383
+ const marker = `${path.sep}.git${path.sep}worktrees${path.sep}`;
1384
+ const idx = resolved.indexOf(marker);
1385
+ if (idx === -1)
1386
+ return null;
1387
+ return resolved.slice(0, idx);
1388
+ }
1389
+ function stripTrailingSeparators(value) {
1390
+ let end = value.length;
1391
+ while (end > 1 && (value[end - 1] === "/" || value[end - 1] === "\\"))
1392
+ end--;
1393
+ return value.slice(0, end);
1394
+ }
1395
+ function basenameOf(value) {
1396
+ const segment = value.split(/[\\/]/).filter(Boolean).pop() ?? null;
1397
+ return segment && segment.length > 0 ? segment : null;
1398
+ }
1399
+ }
1400
+ });
1401
+
1028
1402
  // ../packages/tool-kit/out/hookAdapter.js
1029
1403
  var require_hookAdapter = __commonJS({
1030
1404
  "../packages/tool-kit/out/hookAdapter.js"(exports) {
1031
1405
  "use strict";
1032
1406
  Object.defineProperty(exports, "__esModule", { value: true });
1033
1407
  exports.DEFAULT_API_BASE_URL = void 0;
1408
+ exports.resolveContextHashes = resolveContextHashes;
1034
1409
  exports.loadCliAgentConfig = loadCliAgentConfig;
1035
1410
  exports.deliverHookEvents = deliverHookEvents;
1411
+ var contextRegistry_1 = require_contextRegistry();
1036
1412
  var eventLog_1 = require_eventLog();
1037
1413
  var eventSender_1 = require_eventSender();
1038
1414
  var tokenStore_1 = require_tokenStore();
1415
+ var workContext_1 = require_workContext();
1039
1416
  exports.DEFAULT_API_BASE_URL = "https://api.ascenda.one";
1040
- function loadCliAgentConfig(toolType, sessionIdFromHook) {
1417
+ function resolveContextHashes(cwd) {
1418
+ const workspaceOverride = process.env.ASCENDA_WORKSPACE_HASH?.trim() || null;
1419
+ const projectOverride = process.env.ASCENDA_PROJECT_HASH?.trim() || null;
1420
+ if (workspaceOverride && projectOverride)
1421
+ return { workspaceHash: workspaceOverride, projectHash: projectOverride };
1422
+ const context = (0, workContext_1.deriveWorkContext)(cwd ?? process.cwd());
1423
+ if (context)
1424
+ (0, contextRegistry_1.recordWorkContext)(context);
1425
+ return {
1426
+ workspaceHash: workspaceOverride ?? context?.workspaceHash ?? null,
1427
+ projectHash: projectOverride ?? context?.projectHash ?? null
1428
+ };
1429
+ }
1430
+ function loadCliAgentConfig(toolType, sessionIdFromHook, cwd) {
1041
1431
  const apiBaseUrl = (process.env.ASCENDA_API_BASE_URL ?? exports.DEFAULT_API_BASE_URL).replace(/\/$/, "");
1042
1432
  const toolInstallationIdRaw = process.env.ASCENDA_TOOL_INSTALLATION_ID;
1043
1433
  if (!toolInstallationIdRaw)
@@ -1050,13 +1440,15 @@ var require_hookAdapter = __commonJS({
1050
1440
  throw new Error("Missing ASCENDA_EVENT_WRITE_TOKEN (or token file)");
1051
1441
  if (!fileToken)
1052
1442
  (0, tokenStore_1.persistEventWriteToken)(tokenFilePath, eventWriteToken);
1443
+ const contextHashes = resolveContextHashes(cwd);
1053
1444
  return {
1054
1445
  apiBaseUrl,
1055
1446
  toolInstallationId,
1056
1447
  eventWriteToken,
1057
1448
  tokenFilePath,
1058
1449
  sessionId: process.env.ASCENDA_SESSION_ID ?? sessionIdFromHook ?? null,
1059
- workspaceHash: process.env.ASCENDA_WORKSPACE_HASH ?? null,
1450
+ workspaceHash: contextHashes.workspaceHash,
1451
+ projectHash: contextHashes.projectHash,
1060
1452
  // Agents await command hooks; fail fast rather than stall the user's turn.
1061
1453
  timeoutMs: parsePositiveInt(process.env.ASCENDA_HTTP_TIMEOUT_MS) ?? 3e3
1062
1454
  };
@@ -1067,11 +1459,12 @@ var require_hookAdapter = __commonJS({
1067
1459
  const notice = options.onNotice ?? ((message) => console.error(message));
1068
1460
  let config2;
1069
1461
  try {
1070
- config2 = loadCliAgentConfig(options.toolType, options.sessionId);
1462
+ config2 = loadCliAgentConfig(options.toolType, options.sessionId, options.cwd);
1071
1463
  } catch (error2) {
1072
1464
  const logFile = (0, eventLog_1.resolveEventLogPath)();
1073
1465
  if (!logFile)
1074
1466
  throw error2;
1467
+ const contextHashes = resolveContextHashes(options.cwd);
1075
1468
  for (const event of events) {
1076
1469
  (0, eventLog_1.appendEventLog)(logFile, {
1077
1470
  loggedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1080,7 +1473,8 @@ var require_hookAdapter = __commonJS({
1080
1473
  toolInstallationId: `${options.toolType}:unpaired`,
1081
1474
  source: options.source,
1082
1475
  sessionId: options.sessionId ?? null,
1083
- workspaceHash: process.env.ASCENDA_WORKSPACE_HASH ?? null
1476
+ workspaceHash: contextHashes.workspaceHash,
1477
+ projectHash: contextHashes.projectHash
1084
1478
  }, event)
1085
1479
  });
1086
1480
  }
@@ -1094,6 +1488,7 @@ var require_hookAdapter = __commonJS({
1094
1488
  tokenFilePath: config2.tokenFilePath,
1095
1489
  sessionId: config2.sessionId,
1096
1490
  workspaceHash: config2.workspaceHash,
1491
+ projectHash: config2.projectHash,
1097
1492
  timeoutMs: config2.timeoutMs
1098
1493
  });
1099
1494
  for (const event of events) {
@@ -1199,89 +1594,6 @@ var require_turnState = __commonJS({
1199
1594
  }
1200
1595
  });
1201
1596
 
1202
- // ../packages/tool-kit/out/salt.js
1203
- var require_salt = __commonJS({
1204
- "../packages/tool-kit/out/salt.js"(exports) {
1205
- "use strict";
1206
- var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
1207
- if (k2 === void 0) k2 = k;
1208
- var desc = Object.getOwnPropertyDescriptor(m, k);
1209
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
1210
- desc = { enumerable: true, get: function() {
1211
- return m[k];
1212
- } };
1213
- }
1214
- Object.defineProperty(o, k2, desc);
1215
- } : function(o, m, k, k2) {
1216
- if (k2 === void 0) k2 = k;
1217
- o[k2] = m[k];
1218
- });
1219
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
1220
- Object.defineProperty(o, "default", { enumerable: true, value: v });
1221
- } : function(o, v) {
1222
- o["default"] = v;
1223
- });
1224
- var __importStar = exports && exports.__importStar || /* @__PURE__ */ function() {
1225
- var ownKeys = function(o) {
1226
- ownKeys = Object.getOwnPropertyNames || function(o2) {
1227
- var ar = [];
1228
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
1229
- return ar;
1230
- };
1231
- return ownKeys(o);
1232
- };
1233
- return function(mod) {
1234
- if (mod && mod.__esModule) return mod;
1235
- var result = {};
1236
- if (mod != null) {
1237
- for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
1238
- }
1239
- __setModuleDefault(result, mod);
1240
- return result;
1241
- };
1242
- }();
1243
- Object.defineProperty(exports, "__esModule", { value: true });
1244
- exports.machineSaltFilePath = machineSaltFilePath;
1245
- exports.readOrCreateMachineSalt = readOrCreateMachineSalt;
1246
- exports.hashWithMachineSalt = hashWithMachineSalt;
1247
- var crypto = __importStar(__require("crypto"));
1248
- var fs = __importStar(__require("fs"));
1249
- var os = __importStar(__require("os"));
1250
- var path = __importStar(__require("path"));
1251
- function machineSaltFilePath() {
1252
- return path.join(os.homedir(), ".ascenda", "salt");
1253
- }
1254
- var cache = /* @__PURE__ */ new Map();
1255
- function readOrCreateMachineSalt(saltFilePath = machineSaltFilePath()) {
1256
- const hit = cache.get(saltFilePath);
1257
- if (hit)
1258
- return hit;
1259
- const dir = path.dirname(saltFilePath);
1260
- fs.mkdirSync(dir, { recursive: true, mode: 448 });
1261
- let salt;
1262
- try {
1263
- salt = crypto.randomBytes(32).toString("hex");
1264
- fs.writeFileSync(saltFilePath, salt, { encoding: "utf8", mode: 384, flag: "wx" });
1265
- } catch (error2) {
1266
- if (error2.code !== "EEXIST")
1267
- throw error2;
1268
- salt = fs.readFileSync(saltFilePath, "utf8").trim();
1269
- }
1270
- if (process.platform !== "win32") {
1271
- fs.chmodSync(dir, 448);
1272
- fs.chmodSync(saltFilePath, 384);
1273
- }
1274
- cache.set(saltFilePath, salt);
1275
- return salt;
1276
- }
1277
- function hashWithMachineSalt(value, saltFilePath) {
1278
- if (!value)
1279
- return null;
1280
- return crypto.createHash("sha256").update(readOrCreateMachineSalt(saltFilePath)).update("\0").update(value).digest("hex").slice(0, 16);
1281
- }
1282
- }
1283
- });
1284
-
1285
1597
  // ../packages/tool-kit/out/liveBus.js
1286
1598
  var require_liveBus = __commonJS({
1287
1599
  "../packages/tool-kit/out/liveBus.js"(exports) {
@@ -1413,8 +1725,8 @@ var require_out2 = __commonJS({
1413
1725
  "../packages/tool-kit/out/index.js"(exports) {
1414
1726
  "use strict";
1415
1727
  Object.defineProperty(exports, "__esModule", { value: true });
1416
- 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.localHourAt = exports.utcOffsetMinutesAt = exports.isAfterHours = exports.bucketDurationMs = exports.bucketLinesChanged = exports.invitesDebrief = exports.classifyWorkMilestone = exports.isReworkGitAction = exports.classifyGitAction = exports.isVerificationCommand = exports.classifyCommand = void 0;
1417
- exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = exports.postToolEvent = void 0;
1728
+ 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;
1729
+ 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;
1418
1730
  var commandClassifier_1 = require_commandClassifier();
1419
1731
  Object.defineProperty(exports, "classifyCommand", { enumerable: true, get: function() {
1420
1732
  return commandClassifier_1.classifyCommand;
@@ -1447,6 +1759,12 @@ var require_out2 = __commonJS({
1447
1759
  Object.defineProperty(exports, "isAfterHours", { enumerable: true, get: function() {
1448
1760
  return afterHours_1.isAfterHours;
1449
1761
  } });
1762
+ Object.defineProperty(exports, "isOutsideBusinessHours", { enumerable: true, get: function() {
1763
+ return afterHours_1.isOutsideBusinessHours;
1764
+ } });
1765
+ Object.defineProperty(exports, "BUSINESS_DAY", { enumerable: true, get: function() {
1766
+ return afterHours_1.BUSINESS_DAY;
1767
+ } });
1450
1768
  Object.defineProperty(exports, "utcOffsetMinutesAt", { enumerable: true, get: function() {
1451
1769
  return afterHours_1.utcOffsetMinutesAt;
1452
1770
  } });
@@ -1511,6 +1829,9 @@ var require_out2 = __commonJS({
1511
1829
  Object.defineProperty(exports, "loadCliAgentConfig", { enumerable: true, get: function() {
1512
1830
  return hookAdapter_1.loadCliAgentConfig;
1513
1831
  } });
1832
+ Object.defineProperty(exports, "resolveContextHashes", { enumerable: true, get: function() {
1833
+ return hookAdapter_1.resolveContextHashes;
1834
+ } });
1514
1835
  var turnState_1 = require_turnState();
1515
1836
  Object.defineProperty(exports, "consumeTurnDurationMs", { enumerable: true, get: function() {
1516
1837
  return turnState_1.consumeTurnDurationMs;
@@ -1554,6 +1875,23 @@ var require_out2 = __commonJS({
1554
1875
  Object.defineProperty(exports, "hashWithMachineSalt", { enumerable: true, get: function() {
1555
1876
  return salt_1.hashWithMachineSalt;
1556
1877
  } });
1878
+ var workContext_1 = require_workContext();
1879
+ Object.defineProperty(exports, "deriveWorkContext", { enumerable: true, get: function() {
1880
+ return workContext_1.deriveWorkContext;
1881
+ } });
1882
+ var contextRegistry_1 = require_contextRegistry();
1883
+ Object.defineProperty(exports, "recordWorkContext", { enumerable: true, get: function() {
1884
+ return contextRegistry_1.recordWorkContext;
1885
+ } });
1886
+ Object.defineProperty(exports, "recordWorkContextAlias", { enumerable: true, get: function() {
1887
+ return contextRegistry_1.recordWorkContextAlias;
1888
+ } });
1889
+ Object.defineProperty(exports, "readWorkContextRegistry", { enumerable: true, get: function() {
1890
+ return contextRegistry_1.readWorkContextRegistry;
1891
+ } });
1892
+ Object.defineProperty(exports, "workContextRegistryFilePath", { enumerable: true, get: function() {
1893
+ return contextRegistry_1.workContextRegistryFilePath;
1894
+ } });
1557
1895
  var liveBus_1 = require_liveBus();
1558
1896
  Object.defineProperty(exports, "emitLiveSignal", { enumerable: true, get: function() {
1559
1897
  return liveBus_1.emitLiveSignal;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "publishConfig": { "access": "public" },
3
3
  "name": "@ascenda-one/agent-mcp",
4
- "version": "0.1.12",
4
+ "version": "0.1.13",
5
5
  "description": "MCP server exposing ascenda_emit_work_signal — the one submission interface for agent-observed (semantic) work-friction signals.",
6
6
  "repository": {
7
7
  "type": "git",