@ascenda-one/agent-mcp 0.1.18 → 0.1.20

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 +98 -12
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -587,7 +587,61 @@ var require_out = __commonJS({
587
587
  "../packages/tool-contract/out/index.js"(exports) {
588
588
  "use strict";
589
589
  Object.defineProperty(exports, "__esModule", { value: true });
590
- 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;
590
+ 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 = exports.ASCENDA_ELAPSED_QUANTITIES = exports.ASCENDA_ACTIVE_TIME_QUANTITIES = exports.ASCENDA_TOOL_TYPES = exports.ASCENDA_TELEMETRY_SOURCES = void 0;
591
+ exports.combineDisjointHalves = combineDisjointHalves;
592
+ exports.requireComparableQuantities = requireComparableQuantities;
593
+ exports.ASCENDA_TELEMETRY_SOURCES = [
594
+ "vscode_extension",
595
+ "cursor_mcp",
596
+ "claude_code",
597
+ "copilot_otel",
598
+ "cli_agent",
599
+ "mcp_server",
600
+ "activity_signals",
601
+ "code_forge"
602
+ ];
603
+ exports.ASCENDA_TOOL_TYPES = [
604
+ "vscode_extension",
605
+ "cursor_mcp",
606
+ "claude_code",
607
+ "copilot_otel",
608
+ "cli_agent",
609
+ "mcp_server",
610
+ "github_collector",
611
+ "other"
612
+ ];
613
+ exports.ASCENDA_ACTIVE_TIME_QUANTITIES = [
614
+ "coverage",
615
+ "hands_on",
616
+ "supervising",
617
+ "block_coverage",
618
+ "hands_on_agent_hours",
619
+ "supervising_agent_hours"
620
+ ];
621
+ exports.ASCENDA_ELAPSED_QUANTITIES = {
622
+ coverage: true,
623
+ hands_on: true,
624
+ supervising: true,
625
+ block_coverage: true,
626
+ hands_on_agent_hours: false,
627
+ supervising_agent_hours: false
628
+ };
629
+ var DISJOINT_HALVES = [
630
+ ["hands_on", "supervising", "coverage"],
631
+ ["supervising", "hands_on", "coverage"]
632
+ ];
633
+ function combineDisjointHalves(left, leftQuantity, right, rightQuantity) {
634
+ const pair = DISJOINT_HALVES.find(([a, b]) => a === leftQuantity && b === rightQuantity);
635
+ if (!pair) {
636
+ throw new Error(`'combine-disjoint' combines active-time quantities '${leftQuantity}' and '${rightQuantity}', which do not partition a common whole.`);
637
+ }
638
+ return { total: left + right, quantity: pair[2] };
639
+ }
640
+ function requireComparableQuantities(left, right, operation) {
641
+ if (left !== right) {
642
+ throw new Error(`'${operation}' combines active-time quantities '${left}' and '${right}', which measure different things. See docs/ACTIVE_TIME.md, 'The quantity is the label, not the gap'.`);
643
+ }
644
+ }
591
645
  exports.SEMANTIC_WORK_SIGNAL_EVENT_TYPES = [
592
646
  "approach_churn_detected",
593
647
  "goal_drift_detected",
@@ -1171,12 +1225,11 @@ var require_stateStore = __commonJS({
1171
1225
  exports.shouldAnnounceFailure = shouldAnnounceFailure;
1172
1226
  exports.markFailureNotified = markFailureNotified;
1173
1227
  var fs = __importStar(__require("fs"));
1174
- var os = __importStar(__require("os"));
1175
1228
  var path = __importStar(__require("path"));
1176
1229
  var tokenStore_1 = require_tokenStore();
1177
1230
  function defaultStateFilePath(toolInstallationId) {
1178
1231
  const dir = process.env.ASCENDA_STATE_DIR?.trim();
1179
- const base = dir ? dir : path.join(os.homedir(), ".ascenda", "state");
1232
+ const base = dir ? dir : path.join((0, tokenStore_1.ascendaHome)(), "state");
1180
1233
  return path.join(base, `${(0, tokenStore_1.sanitizeFilePart)(toolInstallationId)}.json`);
1181
1234
  }
1182
1235
  function unresolvedToolInstallationId(toolType) {
@@ -1498,6 +1551,25 @@ var require_outbox = __commonJS({
1498
1551
  }
1499
1552
  });
1500
1553
 
1554
+ // ../packages/tool-kit/out/timeProvider.js
1555
+ var require_timeProvider = __commonJS({
1556
+ "../packages/tool-kit/out/timeProvider.js"(exports) {
1557
+ "use strict";
1558
+ Object.defineProperty(exports, "__esModule", { value: true });
1559
+ exports.systemTimeProvider = void 0;
1560
+ exports.fixedTimeProvider = fixedTimeProvider;
1561
+ exports.systemTimeProvider = {
1562
+ now: () => Date.now()
1563
+ };
1564
+ function fixedTimeProvider(instant) {
1565
+ const ms = typeof instant === "number" ? instant : new Date(instant).valueOf();
1566
+ if (!Number.isFinite(ms))
1567
+ throw new TypeError(`fixedTimeProvider: not a usable instant: ${String(instant)}`);
1568
+ return { now: () => ms };
1569
+ }
1570
+ }
1571
+ });
1572
+
1501
1573
  // ../packages/tool-kit/out/eventSender.js
1502
1574
  var require_eventSender = __commonJS({
1503
1575
  "../packages/tool-kit/out/eventSender.js"(exports) {
@@ -1510,6 +1582,7 @@ var require_eventSender = __commonJS({
1510
1582
  var eventLog_1 = require_eventLog();
1511
1583
  var http_1 = require_http();
1512
1584
  var outbox_1 = require_outbox();
1585
+ var timeProvider_1 = require_timeProvider();
1513
1586
  var tokenStore_1 = require_tokenStore();
1514
1587
  var stateStore_1 = require_stateStore();
1515
1588
  var payload_1 = require_payload();
@@ -1546,9 +1619,12 @@ var require_eventSender = __commonJS({
1546
1619
  lastDrain;
1547
1620
  /** One outbox pass per sender, i.e. per hook process. The hook is on the user's critical path. */
1548
1621
  outboxServiced = false;
1622
+ /** Resolved once, so every clock read in one pass sees the same instant. */
1623
+ time;
1549
1624
  constructor(config2) {
1550
1625
  this.config = config2;
1551
1626
  this.eventWriteToken = config2.eventWriteToken;
1627
+ this.time = config2.timeProvider ?? timeProvider_1.systemTimeProvider;
1552
1628
  }
1553
1629
  async send(mapped) {
1554
1630
  return this.post(buildEventPayload(this.config, mapped));
@@ -1699,7 +1775,7 @@ var require_eventSender = __commonJS({
1699
1775
  * journal's detail says so instead of implying it was kept.
1700
1776
  */
1701
1777
  enqueue(payload) {
1702
- return (0, outbox_1.appendToOutbox)(this.outboxFilePath(), payload);
1778
+ return (0, outbox_1.appendToOutbox)(this.outboxFilePath(), payload, new Date(this.time.now()));
1703
1779
  }
1704
1780
  /**
1705
1781
  * One pass over the outbox: claim it, apply the bounds, and — when sending
@@ -1722,7 +1798,7 @@ var require_eventSender = __commonJS({
1722
1798
  return void 0;
1723
1799
  this.outboxServiced = true;
1724
1800
  const sendEnabled = this.config.outboxDrain ?? (0, outbox_1.outboxDrainEnabled)();
1725
- const claimed = (0, outbox_1.claimOutbox)(this.outboxFilePath());
1801
+ const claimed = (0, outbox_1.claimOutbox)(this.outboxFilePath(), this.time.now());
1726
1802
  if (!claimed) {
1727
1803
  this.lastDrain = { found: 0, discarded: 0, delivered: 0, remaining: 0, sendEnabled };
1728
1804
  return void 0;
@@ -1731,7 +1807,7 @@ var require_eventSender = __commonJS({
1731
1807
  const { kept, discarded } = (0, outbox_1.enforceOutboxBounds)(claimed.entries, {
1732
1808
  maxEntries: this.config.outboxMaxEntries ?? outbox_1.DEFAULT_OUTBOX_MAX_ENTRIES,
1733
1809
  maxAgeMs: this.config.outboxMaxAgeMs ?? outbox_1.DEFAULT_OUTBOX_MAX_AGE_MS
1734
- });
1810
+ }, this.time.now());
1735
1811
  if (claimed.unreadable > 0) {
1736
1812
  discarded.count += claimed.unreadable;
1737
1813
  discarded.reasons.unreadable = claimed.unreadable;
@@ -2600,10 +2676,10 @@ var require_hookAdapter = __commonJS({
2600
2676
  exports.MissingInstallationIdError = MissingInstallationIdError;
2601
2677
  function resolveCliAgentInstallationId(toolType, identity = {}) {
2602
2678
  const fromEnv = process.env.ASCENDA_TOOL_INSTALLATION_ID?.trim();
2603
- if (fromEnv)
2679
+ if (fromEnv && belongsToToolType(toolType, fromEnv))
2604
2680
  return { toolInstallationId: qualify(toolType, fromEnv), source: "env" };
2605
2681
  const fromCredentials = identity.host ? (0, credentials_1.readHostCredentials)(identity.host)?.toolInstallationId?.trim() : void 0;
2606
- if (fromCredentials)
2682
+ if (fromCredentials && belongsToToolType(toolType, fromCredentials))
2607
2683
  return { toolInstallationId: qualify(toolType, fromCredentials), source: "credentials" };
2608
2684
  const candidates = (0, tokenStore_1.listPersistedToolInstallationIds)(toolType);
2609
2685
  if (candidates.length === 1)
@@ -2613,6 +2689,9 @@ var require_hookAdapter = __commonJS({
2613
2689
  function defaultSetupCommand(host) {
2614
2690
  return host ? `npx @ascenda-one/${host.replace(/_cli$/, "")}-hooks setup` : "the agent's setup command";
2615
2691
  }
2692
+ function belongsToToolType(toolType, value) {
2693
+ return !value.includes(":") || value.startsWith(`${toolType}:`);
2694
+ }
2616
2695
  function qualify(toolType, value) {
2617
2696
  return value.includes(":") ? value : `${toolType}:${value}`;
2618
2697
  }
@@ -3153,9 +3232,9 @@ var require_turnState = __commonJS({
3153
3232
  exports.recordTurnStart = recordTurnStart;
3154
3233
  exports.consumeTurnDurationMs = consumeTurnDurationMs;
3155
3234
  var fs = __importStar(__require("fs"));
3156
- var os = __importStar(__require("os"));
3157
3235
  var path = __importStar(__require("path"));
3158
- var stateDir = () => process.env.ASCENDA_STATE_DIR ?? path.join(os.homedir(), ".ascenda", "state");
3236
+ var tokenStore_1 = require_tokenStore();
3237
+ var stateDir = () => process.env.ASCENDA_STATE_DIR ?? path.join((0, tokenStore_1.ascendaHome)(), "state");
3159
3238
  function turnFile(agent, sessionId) {
3160
3239
  return path.join(stateDir(), `${sanitize(agent)}-turn-${sanitize(sessionId)}`);
3161
3240
  }
@@ -3322,8 +3401,8 @@ var require_out2 = __commonJS({
3322
3401
  "use strict";
3323
3402
  Object.defineProperty(exports, "__esModule", { value: true });
3324
3403
  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;
3325
- 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;
3326
- exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = void 0;
3404
+ 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.fixedTimeProvider = exports.systemTimeProvider = 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;
3405
+ exports.isRetryableStatus = exports.parseIngestResponse = exports.postToolEventsBatch = exports.postToolEvent = exports.renewToolToken = void 0;
3327
3406
  var commandClassifier_1 = require_commandClassifier();
3328
3407
  Object.defineProperty(exports, "classifyCommand", { enumerable: true, get: function() {
3329
3408
  return commandClassifier_1.classifyCommand;
@@ -3563,6 +3642,13 @@ var require_out2 = __commonJS({
3563
3642
  Object.defineProperty(exports, "enforceOutboxBounds", { enumerable: true, get: function() {
3564
3643
  return outbox_1.enforceOutboxBounds;
3565
3644
  } });
3645
+ var timeProvider_1 = require_timeProvider();
3646
+ Object.defineProperty(exports, "systemTimeProvider", { enumerable: true, get: function() {
3647
+ return timeProvider_1.systemTimeProvider;
3648
+ } });
3649
+ Object.defineProperty(exports, "fixedTimeProvider", { enumerable: true, get: function() {
3650
+ return timeProvider_1.fixedTimeProvider;
3651
+ } });
3566
3652
  var salt_1 = require_salt();
3567
3653
  Object.defineProperty(exports, "machineSaltFilePath", { enumerable: true, get: function() {
3568
3654
  return salt_1.machineSaltFilePath;
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.18",
4
+ "version": "0.1.20",
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",