exponential-sdk 1.17.0 → 1.20.0
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/index.d.ts +328 -2
- package/dist/index.js +166 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -221,6 +221,24 @@ type DecisionUpdateProcedureInput = {
|
|
|
221
221
|
keyResultId?: string | null;
|
|
222
222
|
adrDocumentId?: string | null;
|
|
223
223
|
};
|
|
224
|
+
type ActionUpsertBySourceInput$1 = {
|
|
225
|
+
sourceType: string;
|
|
226
|
+
sourceId: string;
|
|
227
|
+
name: string;
|
|
228
|
+
workspaceId: string;
|
|
229
|
+
description?: string;
|
|
230
|
+
projectId?: string | null;
|
|
231
|
+
ticketId?: string | null;
|
|
232
|
+
};
|
|
233
|
+
type TimeEntryCreateInput = {
|
|
234
|
+
actionId: string;
|
|
235
|
+
startedAt: Date;
|
|
236
|
+
endedAt: Date;
|
|
237
|
+
source?: 'manual' | 'claude-desktop' | 'agent-run';
|
|
238
|
+
status?: 'PROPOSED' | 'CONFIRMED';
|
|
239
|
+
sourceRef?: string;
|
|
240
|
+
note?: string;
|
|
241
|
+
};
|
|
224
242
|
interface TrpcClient {
|
|
225
243
|
transcription: {
|
|
226
244
|
getAllTranscriptions: {
|
|
@@ -298,6 +316,10 @@ interface TrpcClient {
|
|
|
298
316
|
update: {
|
|
299
317
|
mutate: (input: ActionUpdateInput$1) => Promise<unknown>;
|
|
300
318
|
};
|
|
319
|
+
/** Idempotent create keyed on (workspaceId, sourceType, sourceId). */
|
|
320
|
+
upsertBySource: {
|
|
321
|
+
mutate: (input: ActionUpsertBySourceInput$1) => Promise<unknown>;
|
|
322
|
+
};
|
|
301
323
|
bulkReschedule: {
|
|
302
324
|
mutate: (input: {
|
|
303
325
|
actionIds: string[];
|
|
@@ -521,6 +543,38 @@ interface TrpcClient {
|
|
|
521
543
|
}) => Promise<unknown>;
|
|
522
544
|
};
|
|
523
545
|
};
|
|
546
|
+
timeEntry: {
|
|
547
|
+
/** Explicit-bounds entry; never touches the running Timer (ADR-0061). */
|
|
548
|
+
create: {
|
|
549
|
+
mutate: (input: TimeEntryCreateInput) => Promise<unknown>;
|
|
550
|
+
};
|
|
551
|
+
upsertBySourceRef: {
|
|
552
|
+
mutate: (input: TimeEntryCreateInput & {
|
|
553
|
+
sourceRef: string;
|
|
554
|
+
}) => Promise<unknown>;
|
|
555
|
+
};
|
|
556
|
+
listByDateRange: {
|
|
557
|
+
query: (input: {
|
|
558
|
+
startDate: Date;
|
|
559
|
+
endDate: Date;
|
|
560
|
+
workspaceId?: string | null;
|
|
561
|
+
}) => Promise<unknown[]>;
|
|
562
|
+
};
|
|
563
|
+
/** Human-only; `date` is the start of the day in the caller's timezone. */
|
|
564
|
+
confirmDay: {
|
|
565
|
+
mutate: (input: {
|
|
566
|
+
date: Date;
|
|
567
|
+
workspaceId?: string | null;
|
|
568
|
+
}) => Promise<unknown>;
|
|
569
|
+
};
|
|
570
|
+
/** `date` is the start of the day in the caller's timezone; an agent key reads its owner's day. */
|
|
571
|
+
dayReport: {
|
|
572
|
+
query: (input: {
|
|
573
|
+
date: Date;
|
|
574
|
+
workspaceId?: string | null;
|
|
575
|
+
}) => Promise<unknown>;
|
|
576
|
+
};
|
|
577
|
+
};
|
|
524
578
|
decision: {
|
|
525
579
|
list: {
|
|
526
580
|
query: (input: {
|
|
@@ -1280,7 +1334,9 @@ interface Action {
|
|
|
1280
1334
|
name: string;
|
|
1281
1335
|
} | null;
|
|
1282
1336
|
assignees?: Array<{
|
|
1283
|
-
|
|
1337
|
+
/** Bare form returned by `action.upsertBySource`. */
|
|
1338
|
+
userId?: string;
|
|
1339
|
+
user?: {
|
|
1284
1340
|
id: string;
|
|
1285
1341
|
name: string | null;
|
|
1286
1342
|
email: string | null;
|
|
@@ -1368,6 +1424,30 @@ interface ActionUpdateInput {
|
|
|
1368
1424
|
effortEstimate?: number | null;
|
|
1369
1425
|
blockedByIds?: string[];
|
|
1370
1426
|
}
|
|
1427
|
+
interface ActionUpsertBySourceInput {
|
|
1428
|
+
/** Convention for the Daily worklog: `claude-session`. */
|
|
1429
|
+
sourceType: string;
|
|
1430
|
+
/** The conversation id — re-running with the same pair updates, never duplicates. */
|
|
1431
|
+
sourceId: string;
|
|
1432
|
+
name: string;
|
|
1433
|
+
workspaceId: string;
|
|
1434
|
+
description?: string;
|
|
1435
|
+
/** Must live in `workspaceId`, or the call is NOT_FOUND. */
|
|
1436
|
+
projectId?: string | null;
|
|
1437
|
+
/** Must belong to a product in `workspaceId`, or the call is NOT_FOUND. */
|
|
1438
|
+
ticketId?: string | null;
|
|
1439
|
+
}
|
|
1440
|
+
interface ActionUpsertBySourceResult {
|
|
1441
|
+
action: Action & {
|
|
1442
|
+
ticket?: {
|
|
1443
|
+
id: string;
|
|
1444
|
+
number: number;
|
|
1445
|
+
shortId: string | null;
|
|
1446
|
+
productId: string;
|
|
1447
|
+
} | null;
|
|
1448
|
+
};
|
|
1449
|
+
outcome: 'created' | 'updated';
|
|
1450
|
+
}
|
|
1371
1451
|
/** One action as returned inside a {@link TodaysActions} group. */
|
|
1372
1452
|
interface TodaysActionRow {
|
|
1373
1453
|
id: string;
|
|
@@ -1470,6 +1550,13 @@ declare class ActionsApi {
|
|
|
1470
1550
|
getProjectActions(projectId: string, assigneeId?: string): Promise<Action[]>;
|
|
1471
1551
|
create(input: ActionCreateInput): Promise<Action>;
|
|
1472
1552
|
update(input: ActionUpdateInput): Promise<Action>;
|
|
1553
|
+
/**
|
|
1554
|
+
* One Action per external source: find by (workspaceId, sourceType,
|
|
1555
|
+
* sourceId), refresh its name and links, else create it. `outcome` says
|
|
1556
|
+
* which happened. Agents may call this; the created Action records the
|
|
1557
|
+
* agent's shadow user as creator with `source: "agent"` (ADR-0049).
|
|
1558
|
+
*/
|
|
1559
|
+
upsertBySource(input: ActionUpsertBySourceInput): Promise<ActionUpsertBySourceResult>;
|
|
1473
1560
|
}
|
|
1474
1561
|
|
|
1475
1562
|
interface CommentAuthor {
|
|
@@ -4061,6 +4148,207 @@ declare class SearchApi {
|
|
|
4061
4148
|
global(options: GlobalSearchOptions): Promise<GlobalSearchOutput>;
|
|
4062
4149
|
}
|
|
4063
4150
|
|
|
4151
|
+
type TimeEntryStatus = 'PROPOSED' | 'CONFIRMED';
|
|
4152
|
+
/**
|
|
4153
|
+
* Where an entry came from. `plugin` is the legacy stamp of the in-app Timer
|
|
4154
|
+
* and calendar grids; new writes use the other three. `claude-desktop` is
|
|
4155
|
+
* Proposed time from the Daily worklog, `agent-run` is Agent-run time (an
|
|
4156
|
+
* agent working with no human turns, kept off the owner's attention totals).
|
|
4157
|
+
*/
|
|
4158
|
+
type TimeEntrySource = 'plugin' | 'manual' | 'claude-desktop' | 'agent-run';
|
|
4159
|
+
interface TimeEntry {
|
|
4160
|
+
id: string;
|
|
4161
|
+
/** Whose time it is. Under an agent key this is the agent's OWNER (ADR-0061). */
|
|
4162
|
+
userId: string;
|
|
4163
|
+
actionId: string;
|
|
4164
|
+
workspaceId: string | null;
|
|
4165
|
+
startedAt: Date;
|
|
4166
|
+
endedAt: Date | null;
|
|
4167
|
+
source: string;
|
|
4168
|
+
status: TimeEntryStatus;
|
|
4169
|
+
/** Idempotency key, e.g. `claude-session:<sessionId>#<segmentIndex>`. */
|
|
4170
|
+
sourceRef: string | null;
|
|
4171
|
+
note: string | null;
|
|
4172
|
+
/** The external agent that wrote the row; null for human-made entries. */
|
|
4173
|
+
createdByAgentId: string | null;
|
|
4174
|
+
action: {
|
|
4175
|
+
id: string;
|
|
4176
|
+
name: string;
|
|
4177
|
+
projectId: string | null;
|
|
4178
|
+
workspaceId: string | null;
|
|
4179
|
+
};
|
|
4180
|
+
}
|
|
4181
|
+
interface TimeLogInput {
|
|
4182
|
+
actionId: string;
|
|
4183
|
+
startedAt: Date;
|
|
4184
|
+
endedAt: Date;
|
|
4185
|
+
/** Defaults to `manual` server-side. */
|
|
4186
|
+
source?: Exclude<TimeEntrySource, 'plugin'>;
|
|
4187
|
+
/**
|
|
4188
|
+
* Ignored under an agent key: agent-written entries are always PROPOSED.
|
|
4189
|
+
* A human's entry defaults to CONFIRMED.
|
|
4190
|
+
*/
|
|
4191
|
+
status?: TimeEntryStatus;
|
|
4192
|
+
/**
|
|
4193
|
+
* With a `sourceRef` the write is idempotent per owner: a re-run updates a
|
|
4194
|
+
* PROPOSED entry in place and leaves a CONFIRMED one alone.
|
|
4195
|
+
*/
|
|
4196
|
+
sourceRef?: string;
|
|
4197
|
+
/** One line shown in the day view and list row (max 1000 chars). */
|
|
4198
|
+
note?: string;
|
|
4199
|
+
}
|
|
4200
|
+
/**
|
|
4201
|
+
* `created` / `updated` — proposed pieces were written; `left` — a CONFIRMED
|
|
4202
|
+
* row already carries this ref and was not touched; `merged` — manual time
|
|
4203
|
+
* on the same Action covers it, so the manual entries were annotated instead
|
|
4204
|
+
* (V2, manual wins); `dropped` — manual time on other Actions covered every
|
|
4205
|
+
* minute, nothing written.
|
|
4206
|
+
*/
|
|
4207
|
+
type TimeLogOutcome = 'created' | 'updated' | 'left' | 'merged' | 'dropped';
|
|
4208
|
+
interface TimeLogResult {
|
|
4209
|
+
/** The first written piece, or the untouched CONFIRMED row; null for merged/dropped. */
|
|
4210
|
+
entry: TimeEntry | null;
|
|
4211
|
+
outcome: TimeLogOutcome;
|
|
4212
|
+
/** Every piece written — several when manual time on another Action split the proposal. */
|
|
4213
|
+
pieces?: TimeEntry[];
|
|
4214
|
+
/** Manual entry ids whose note now carries the conversation reference. */
|
|
4215
|
+
mergedInto?: string[];
|
|
4216
|
+
}
|
|
4217
|
+
interface DayReportEntry extends TimeEntry {
|
|
4218
|
+
/** Whole minutes inside the day window (a running entry ends "now"). */
|
|
4219
|
+
minutes: number;
|
|
4220
|
+
/** `ticket.productId ?? project.productId ?? null`. */
|
|
4221
|
+
productId: string | null;
|
|
4222
|
+
productName: string | null;
|
|
4223
|
+
isAgentRun: boolean;
|
|
4224
|
+
flags: Array<'forgotten-timer'>;
|
|
4225
|
+
action: TimeEntry['action'] & {
|
|
4226
|
+
ticketId: string | null;
|
|
4227
|
+
project: {
|
|
4228
|
+
id: string;
|
|
4229
|
+
name: string;
|
|
4230
|
+
productId: string | null;
|
|
4231
|
+
} | null;
|
|
4232
|
+
ticket: {
|
|
4233
|
+
id: string;
|
|
4234
|
+
number: number;
|
|
4235
|
+
shortId: string | null;
|
|
4236
|
+
title: string;
|
|
4237
|
+
productId: string;
|
|
4238
|
+
} | null;
|
|
4239
|
+
};
|
|
4240
|
+
}
|
|
4241
|
+
interface DayReportProductRow {
|
|
4242
|
+
/** Null is Unassigned time. */
|
|
4243
|
+
productId: string | null;
|
|
4244
|
+
name: string;
|
|
4245
|
+
/** Overlap-split minutes; the rows sum to `attentionMinutes`. */
|
|
4246
|
+
minutes: number;
|
|
4247
|
+
}
|
|
4248
|
+
interface DayReportActionRow {
|
|
4249
|
+
actionId: string;
|
|
4250
|
+
name: string;
|
|
4251
|
+
/** Overlap-split minutes; the rows sum to `attentionMinutes`. */
|
|
4252
|
+
minutes: number;
|
|
4253
|
+
/** Plain sum of the Action's non-agent-run entries. */
|
|
4254
|
+
sessionMinutes: number;
|
|
4255
|
+
agentRunMinutes: number;
|
|
4256
|
+
productId: string | null;
|
|
4257
|
+
productName: string | null;
|
|
4258
|
+
projectId: string | null;
|
|
4259
|
+
projectName: string | null;
|
|
4260
|
+
ticket: {
|
|
4261
|
+
id: string;
|
|
4262
|
+
number: number;
|
|
4263
|
+
shortId: string | null;
|
|
4264
|
+
title: string;
|
|
4265
|
+
} | null;
|
|
4266
|
+
proposedCount: number;
|
|
4267
|
+
}
|
|
4268
|
+
/**
|
|
4269
|
+
* One day of a person's time — the same numbers the `/time` Day tab shows.
|
|
4270
|
+
* Attention minutes count each covered minute once; session minutes are the
|
|
4271
|
+
* plain sum; Agent-run time is kept off both and reported on its own.
|
|
4272
|
+
*/
|
|
4273
|
+
interface DayReport {
|
|
4274
|
+
dayStart: Date;
|
|
4275
|
+
dayEnd: Date;
|
|
4276
|
+
entries: DayReportEntry[];
|
|
4277
|
+
attentionMinutes: number;
|
|
4278
|
+
sessionMinutes: number;
|
|
4279
|
+
agentRunMinutes: number;
|
|
4280
|
+
byProduct: DayReportProductRow[];
|
|
4281
|
+
byAction: DayReportActionRow[];
|
|
4282
|
+
/** Non-agent-run entries whose Action has neither Ticket nor Project. */
|
|
4283
|
+
unassignedCount: number;
|
|
4284
|
+
proposedCount: number;
|
|
4285
|
+
flags: Array<{
|
|
4286
|
+
entryId: string;
|
|
4287
|
+
flag: 'forgotten-timer';
|
|
4288
|
+
}>;
|
|
4289
|
+
}
|
|
4290
|
+
interface TimeConfirmDayResult {
|
|
4291
|
+
/** Proposed entries flipped to CONFIRMED. */
|
|
4292
|
+
confirmed: number;
|
|
4293
|
+
}
|
|
4294
|
+
interface TimeLogBatchResult {
|
|
4295
|
+
index: number;
|
|
4296
|
+
success: boolean;
|
|
4297
|
+
sourceRef?: string;
|
|
4298
|
+
/** Null when the outcome is `merged` or `dropped`. */
|
|
4299
|
+
entry?: TimeEntry | null;
|
|
4300
|
+
outcome?: TimeLogOutcome;
|
|
4301
|
+
pieces?: TimeEntry[];
|
|
4302
|
+
mergedInto?: string[];
|
|
4303
|
+
error?: string;
|
|
4304
|
+
}
|
|
4305
|
+
/**
|
|
4306
|
+
* Time entries — the Daily worklog's write path (ADR-0061).
|
|
4307
|
+
*
|
|
4308
|
+
* The thing to know: an entry always belongs to the person whose time it
|
|
4309
|
+
* was. Called with an external-agent key, {@link log} writes an entry OWNED
|
|
4310
|
+
* by the agent's owner, records the agent as author and forces it to
|
|
4311
|
+
* `PROPOSED`; it shows on the owner's `/time` with a "proposed" chip and
|
|
4312
|
+
* stays out of `Action.timeSpentMins` until the owner confirms the day.
|
|
4313
|
+
* Manual time is never altered by these calls.
|
|
4314
|
+
*/
|
|
4315
|
+
declare class TimeApi {
|
|
4316
|
+
private client;
|
|
4317
|
+
constructor(client: TrpcClient);
|
|
4318
|
+
/**
|
|
4319
|
+
* Log one completed entry with explicit bounds. Never starts, stops or
|
|
4320
|
+
* alters the running Timer. With `sourceRef` the call is an upsert keyed
|
|
4321
|
+
* on (owner, sourceRef); without it every call creates a row.
|
|
4322
|
+
*/
|
|
4323
|
+
log(input: TimeLogInput): Promise<TimeLogResult>;
|
|
4324
|
+
/**
|
|
4325
|
+
* Log many entries, one call each and in order, so a failure names the
|
|
4326
|
+
* entry it belonged to instead of rejecting the whole batch. `defaults`
|
|
4327
|
+
* fill any field an entry leaves out.
|
|
4328
|
+
*/
|
|
4329
|
+
logBatch(entries: Partial<TimeLogInput>[], defaults?: Partial<TimeLogInput>): Promise<TimeLogBatchResult[]>;
|
|
4330
|
+
/**
|
|
4331
|
+
* Confirm a day: every PROPOSED entry of yours that starts on that local
|
|
4332
|
+
* calendar day becomes CONFIRMED and the Actions' spent time moves. Human
|
|
4333
|
+
* only — the server refuses agent keys, so run this with personal
|
|
4334
|
+
* credentials. A day with nothing proposed returns `{ confirmed: 0 }`.
|
|
4335
|
+
*/
|
|
4336
|
+
confirmDay(date: Date | string, workspaceId?: string): Promise<TimeConfirmDayResult>;
|
|
4337
|
+
/**
|
|
4338
|
+
* The day report for one local calendar day: entries joined to Action,
|
|
4339
|
+
* Ticket, Project and Product, attention / session / agent-run minutes,
|
|
4340
|
+
* the overlap-split roll-ups and the counts — exactly what the `/time` Day
|
|
4341
|
+
* tab and the Daily summary's Yesterday line read. Under an agent key the
|
|
4342
|
+
* report is the OWNER's day.
|
|
4343
|
+
*/
|
|
4344
|
+
dayReport(date: Date | string, workspaceId?: string): Promise<DayReport>;
|
|
4345
|
+
/**
|
|
4346
|
+
* The caller's entries that touch one calendar day (local time), oldest
|
|
4347
|
+
* first, each with its `status`. Pass `YYYY-MM-DD` or a Date.
|
|
4348
|
+
*/
|
|
4349
|
+
list(date: Date | string, workspaceId?: string): Promise<TimeEntry[]>;
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4064
4352
|
interface ExponentialConfig {
|
|
4065
4353
|
apiUrl: string;
|
|
4066
4354
|
token: string;
|
|
@@ -4083,6 +4371,42 @@ declare function clearConfig(): void;
|
|
|
4083
4371
|
declare function isAuthenticated(): boolean;
|
|
4084
4372
|
declare function getConfigPath(): string;
|
|
4085
4373
|
|
|
4374
|
+
/**
|
|
4375
|
+
* Worklog segments (CONTEXT.md "Worklog segment"): cut a conversation into
|
|
4376
|
+
* the stretches of a person's attention it actually held. Pure — it lives in
|
|
4377
|
+
* the SDK because the Daily worklog that needs it runs outside the app
|
|
4378
|
+
* (decision 2026-09-12).
|
|
4379
|
+
*/
|
|
4380
|
+
interface ConversationMessage {
|
|
4381
|
+
at: Date | string;
|
|
4382
|
+
role: 'user' | 'assistant';
|
|
4383
|
+
}
|
|
4384
|
+
interface WorklogSegment {
|
|
4385
|
+
start: Date;
|
|
4386
|
+
end: Date;
|
|
4387
|
+
/** Number of the person's messages inside. `0` marks an Agent-run stretch. */
|
|
4388
|
+
humanTurns: number;
|
|
4389
|
+
}
|
|
4390
|
+
/** Silence between the person's messages that ends a segment. */
|
|
4391
|
+
declare const DEFAULT_GAP_MINUTES = 30;
|
|
4392
|
+
/** Segment bounds are rounded outward to this grain. */
|
|
4393
|
+
declare const ROUND_MINUTES = 5;
|
|
4394
|
+
/**
|
|
4395
|
+
* Rules:
|
|
4396
|
+
* - a segment opens at a user message and, as long as the person keeps
|
|
4397
|
+
* replying within `gapMinutes` of their previous message, runs to the
|
|
4398
|
+
* last reply before the next gap (CONTEXT.md: "starts at the person's
|
|
4399
|
+
* first message and ends at the last reply");
|
|
4400
|
+
* - the exception is unattended work: once the assistant has been talking
|
|
4401
|
+
* alone for longer than `gapMinutes` since the person's last message, the
|
|
4402
|
+
* rest of that run — when it lasts longer than `gapMinutes` itself — is
|
|
4403
|
+
* a separate segment with `humanTurns: 0`, and the person's segment ends
|
|
4404
|
+
* at the last message inside the window. A shorter tail is just the reply
|
|
4405
|
+
* and stays in the person's segment;
|
|
4406
|
+
* - every segment is rounded outward to 5 minutes.
|
|
4407
|
+
*/
|
|
4408
|
+
declare function segmentConversation(messages: ConversationMessage[], gapMinutes?: number): WorklogSegment[];
|
|
4409
|
+
|
|
4086
4410
|
declare class ExponentialClient {
|
|
4087
4411
|
private config;
|
|
4088
4412
|
private client;
|
|
@@ -4112,10 +4436,12 @@ declare class ExponentialClient {
|
|
|
4112
4436
|
requirements: RequirementsApi;
|
|
4113
4437
|
scopes: ScopesApi;
|
|
4114
4438
|
search: SearchApi;
|
|
4439
|
+
/** Time entries — the Daily worklog's write path (ADR-0061). */
|
|
4440
|
+
time: TimeApi;
|
|
4115
4441
|
constructor(config: {
|
|
4116
4442
|
token: string;
|
|
4117
4443
|
apiUrl: string;
|
|
4118
4444
|
});
|
|
4119
4445
|
}
|
|
4120
4446
|
|
|
4121
|
-
export { type Action, type ActionComment, type ActionCommentAddInput, type ActionCommentUpdateInput, type ActionCreateInput, type ActionOutput, type ActionStatus, type ActionUpdateInput, type ActionsListOutput, type AddInteractionInput, type Area, type AreaCreateInput, type AreaListOptions, type CommentAuthor, type Contact, type ContactCreateInput, type ContactInteraction, type ContactListOutput, type ContactUpdateInput, type ContactsListOptions, type Deal, type DealActivity, type DealCreateInput, type DealMoveInput, type DealUpdateInput, type Decision, type DecisionAdrRef, type DecisionChainRef, type DecisionCreateInput, type DecisionDecider, type DecisionDeciderInput, type DecisionEvidenceTurn, type DecisionFeatureRef, type DecisionLink, type DecisionListOptions, type DecisionListRow, type DecisionMeetingRef, type DecisionOccurrenceRef, type DecisionProductRef, type DecisionProjectRef, type DecisionReviewState, type DecisionSetStatusInput, type DecisionSource, type DecisionStatus, type DecisionTicketRef, type DecisionUpdateInput, type DecisionUserRef, type DraftDecisionsResult, type EnrichContactResult, type Epic, type EpicCreateInput, type EpicListOptions, type EpicPriority, type EpicStatus, type EpicUpdateInput, ExponentialClient, type ExponentialConfig, type Feature, type FeatureComment, type FeatureCommentCreateInput, type FeatureCommentReplyInput, type FeatureCommentThreadInput, type FeatureCommentUpdateInput, type FeatureCreateInput, type FeatureKeyResultLink, type FeatureLinkPageInput, type FeatureListOptions, type FeatureScope, type FeatureScopeStatus, type FeatureStatus, type FeatureUpdateInput, type GlobalSearchOptions, type GlobalSearchOutput, type Goal, type GoalChildSummary, type GoalComment, type GoalCommentAddInput, type GoalCommentUpdateInput, type GoalCreateInput, type GoalHealth, type GoalKeyResultSummary, type GoalLifeDomain, type GoalListOptions, type GoalPeriod, type GoalProjectSummary, type GoalSetParentInput, type GoalSetStatusInput, type GoalStats, type GoalStatsOptions, type GoalStatus, type GoalTreeNode, type GoalTreeOptions, type GoalUpdateInput, type GoalUserSummary, type GoalWritableStatus, type InteractionDirection, type InteractionType, type KanbanStatus, type KeyResult, type KeyResultByObjectiveOptions, type KeyResultCheckIn, type KeyResultCheckInInput, type KeyResultCreateInput, type KeyResultFeatureLink, type KeyResultListOptions, type KeyResultProjectLink, type KeyResultStatus, type KeyResultUnit, type KeyResultUpdateInput, type KnowledgePage, type LabelCreateInput, type LabelListOptions, type ListForEntityInput, type Meeting, type MeetingActionSummary, type MeetingCreateInput, type MeetingDecisions, type MeetingListOptions, type MeetingParticipant, type MeetingParticipantInput, type MeetingProjectRef, type MeetingSourceIntegration, type MeetingTypeFilter, type MeetingUpdateInput, type MeetingWorkspaceRef, type ObjectiveWithKeyResults, type Organization, type OrganizationCreateInput, type OrganizationListOutput, type OrganizationSize, type OrganizationsListOptions, type OverdueCohort, type OverdueTriage, type OverdueTriageRow, type PageComment, type PageCommentCreateInput, type PageCommentUpdateInput, type PageCreateInput, type PageListOptions, type PageUpdateInput, type Pipeline, type PipelineStage, type Priority, type Product, type ProductCreateInput, type ProductUpdateInput, type Project, type ProjectDetail, type ProjectKeyResultLink, type ProjectOutput, type ProjectPriority, type ProjectStatus, type ProjectUpdateInput, type ProjectsListOptions, type ProjectsListOutput, type Requirement, type RequirementCreateInput, type RequirementKind, type RequirementListOptions, type ScopeCreateInput, type ScopeListOptions, type ScopeUpdateInput, type SearchResult, type SearchResultType, type SearchResultWorkspace, type SetEntityTagsInput, type SetEntityTagsResult, type Tag, type TagEntityType, type TagListResult, type Ticket, type TicketAssignee, type TicketComment, type TicketCommentAddInput, type TicketCommentUpdateInput, type TicketCreateInput, type TicketDependencyEdge, type TicketDetail, type TicketListOptions, type TicketSearchOptions, type TicketStatus, type TicketType, type TicketUpdateInput, type TodaysActionRow, type TodaysActions, type TodaysActionsGroup, type UserStory, type UserStoryCreateInput, type UserStoryListOptions, type UserStoryUpdateInput, type Workspace, type WorkspaceMember, type WorkspaceOutput, type WorkspacesListOutput, clearConfig, createConfigStore, getConfigPath, isAuthenticated, isTRPCError, loadConfig, saveConfig };
|
|
4447
|
+
export { type Action, type ActionComment, type ActionCommentAddInput, type ActionCommentUpdateInput, type ActionCreateInput, type ActionOutput, type ActionStatus, type ActionUpdateInput, type ActionUpsertBySourceInput, type ActionUpsertBySourceResult, type ActionsListOutput, type AddInteractionInput, type Area, type AreaCreateInput, type AreaListOptions, type CommentAuthor, type Contact, type ContactCreateInput, type ContactInteraction, type ContactListOutput, type ContactUpdateInput, type ContactsListOptions, type ConversationMessage, DEFAULT_GAP_MINUTES, type DayReport, type DayReportActionRow, type DayReportEntry, type DayReportProductRow, type Deal, type DealActivity, type DealCreateInput, type DealMoveInput, type DealUpdateInput, type Decision, type DecisionAdrRef, type DecisionChainRef, type DecisionCreateInput, type DecisionDecider, type DecisionDeciderInput, type DecisionEvidenceTurn, type DecisionFeatureRef, type DecisionLink, type DecisionListOptions, type DecisionListRow, type DecisionMeetingRef, type DecisionOccurrenceRef, type DecisionProductRef, type DecisionProjectRef, type DecisionReviewState, type DecisionSetStatusInput, type DecisionSource, type DecisionStatus, type DecisionTicketRef, type DecisionUpdateInput, type DecisionUserRef, type DraftDecisionsResult, type EnrichContactResult, type Epic, type EpicCreateInput, type EpicListOptions, type EpicPriority, type EpicStatus, type EpicUpdateInput, ExponentialClient, type ExponentialConfig, type Feature, type FeatureComment, type FeatureCommentCreateInput, type FeatureCommentReplyInput, type FeatureCommentThreadInput, type FeatureCommentUpdateInput, type FeatureCreateInput, type FeatureKeyResultLink, type FeatureLinkPageInput, type FeatureListOptions, type FeatureScope, type FeatureScopeStatus, type FeatureStatus, type FeatureUpdateInput, type GlobalSearchOptions, type GlobalSearchOutput, type Goal, type GoalChildSummary, type GoalComment, type GoalCommentAddInput, type GoalCommentUpdateInput, type GoalCreateInput, type GoalHealth, type GoalKeyResultSummary, type GoalLifeDomain, type GoalListOptions, type GoalPeriod, type GoalProjectSummary, type GoalSetParentInput, type GoalSetStatusInput, type GoalStats, type GoalStatsOptions, type GoalStatus, type GoalTreeNode, type GoalTreeOptions, type GoalUpdateInput, type GoalUserSummary, type GoalWritableStatus, type InteractionDirection, type InteractionType, type KanbanStatus, type KeyResult, type KeyResultByObjectiveOptions, type KeyResultCheckIn, type KeyResultCheckInInput, type KeyResultCreateInput, type KeyResultFeatureLink, type KeyResultListOptions, type KeyResultProjectLink, type KeyResultStatus, type KeyResultUnit, type KeyResultUpdateInput, type KnowledgePage, type LabelCreateInput, type LabelListOptions, type ListForEntityInput, type Meeting, type MeetingActionSummary, type MeetingCreateInput, type MeetingDecisions, type MeetingListOptions, type MeetingParticipant, type MeetingParticipantInput, type MeetingProjectRef, type MeetingSourceIntegration, type MeetingTypeFilter, type MeetingUpdateInput, type MeetingWorkspaceRef, type ObjectiveWithKeyResults, type Organization, type OrganizationCreateInput, type OrganizationListOutput, type OrganizationSize, type OrganizationsListOptions, type OverdueCohort, type OverdueTriage, type OverdueTriageRow, type PageComment, type PageCommentCreateInput, type PageCommentUpdateInput, type PageCreateInput, type PageListOptions, type PageUpdateInput, type Pipeline, type PipelineStage, type Priority, type Product, type ProductCreateInput, type ProductUpdateInput, type Project, type ProjectDetail, type ProjectKeyResultLink, type ProjectOutput, type ProjectPriority, type ProjectStatus, type ProjectUpdateInput, type ProjectsListOptions, type ProjectsListOutput, ROUND_MINUTES, type Requirement, type RequirementCreateInput, type RequirementKind, type RequirementListOptions, type ScopeCreateInput, type ScopeListOptions, type ScopeUpdateInput, type SearchResult, type SearchResultType, type SearchResultWorkspace, type SetEntityTagsInput, type SetEntityTagsResult, type Tag, type TagEntityType, type TagListResult, type Ticket, type TicketAssignee, type TicketComment, type TicketCommentAddInput, type TicketCommentUpdateInput, type TicketCreateInput, type TicketDependencyEdge, type TicketDetail, type TicketListOptions, type TicketSearchOptions, type TicketStatus, type TicketType, type TicketUpdateInput, TimeApi, type TimeConfirmDayResult, type TimeEntry, type TimeEntrySource, type TimeEntryStatus, type TimeLogBatchResult, type TimeLogInput, type TimeLogOutcome, type TimeLogResult, type TodaysActionRow, type TodaysActions, type TodaysActionsGroup, type UserStory, type UserStoryCreateInput, type UserStoryListOptions, type UserStoryUpdateInput, type WorklogSegment, type Workspace, type WorkspaceMember, type WorkspaceOutput, type WorkspacesListOutput, clearConfig, createConfigStore, getConfigPath, isAuthenticated, isTRPCError, loadConfig, saveConfig, segmentConversation };
|
package/dist/index.js
CHANGED
|
@@ -144,6 +144,15 @@ var ActionsApi = class {
|
|
|
144
144
|
async update(input) {
|
|
145
145
|
return await this.client.action.update.mutate(input);
|
|
146
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* One Action per external source: find by (workspaceId, sourceType,
|
|
149
|
+
* sourceId), refresh its name and links, else create it. `outcome` says
|
|
150
|
+
* which happened. Agents may call this; the created Action records the
|
|
151
|
+
* agent's shadow user as creator with `source: "agent"` (ADR-0049).
|
|
152
|
+
*/
|
|
153
|
+
async upsertBySource(input) {
|
|
154
|
+
return await this.client.action.upsertBySource.mutate(input);
|
|
155
|
+
}
|
|
147
156
|
};
|
|
148
157
|
|
|
149
158
|
// src/actionComments.ts
|
|
@@ -1152,6 +1161,101 @@ var SearchApi = class {
|
|
|
1152
1161
|
}
|
|
1153
1162
|
};
|
|
1154
1163
|
|
|
1164
|
+
// src/time.ts
|
|
1165
|
+
function startOfLocalDay(date) {
|
|
1166
|
+
const d = typeof date === "string" && /^\d{4}-\d{2}-\d{2}$/.test(date) ? /* @__PURE__ */ new Date(`${date}T00:00:00`) : new Date(date);
|
|
1167
|
+
if (Number.isNaN(d.getTime())) {
|
|
1168
|
+
throw new Error(`Invalid date: "${String(date)}". Use YYYY-MM-DD or an ISO timestamp.`);
|
|
1169
|
+
}
|
|
1170
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
1171
|
+
}
|
|
1172
|
+
var TimeApi = class {
|
|
1173
|
+
constructor(client) {
|
|
1174
|
+
this.client = client;
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Log one completed entry with explicit bounds. Never starts, stops or
|
|
1178
|
+
* alters the running Timer. With `sourceRef` the call is an upsert keyed
|
|
1179
|
+
* on (owner, sourceRef); without it every call creates a row.
|
|
1180
|
+
*/
|
|
1181
|
+
async log(input) {
|
|
1182
|
+
if (input.sourceRef) {
|
|
1183
|
+
return await this.client.timeEntry.upsertBySourceRef.mutate({
|
|
1184
|
+
...input,
|
|
1185
|
+
sourceRef: input.sourceRef
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
const entry = await this.client.timeEntry.create.mutate(input);
|
|
1189
|
+
return { entry, outcome: "created", pieces: [entry], mergedInto: [] };
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Log many entries, one call each and in order, so a failure names the
|
|
1193
|
+
* entry it belonged to instead of rejecting the whole batch. `defaults`
|
|
1194
|
+
* fill any field an entry leaves out.
|
|
1195
|
+
*/
|
|
1196
|
+
async logBatch(entries, defaults = {}) {
|
|
1197
|
+
const results = [];
|
|
1198
|
+
for (const [index, item] of entries.entries()) {
|
|
1199
|
+
const merged = { ...defaults, ...item };
|
|
1200
|
+
const sourceRef = merged.sourceRef;
|
|
1201
|
+
try {
|
|
1202
|
+
if (!merged.actionId) throw new Error("actionId is required");
|
|
1203
|
+
if (!merged.startedAt || !merged.endedAt) {
|
|
1204
|
+
throw new Error("startedAt and endedAt are required");
|
|
1205
|
+
}
|
|
1206
|
+
const result = await this.log(merged);
|
|
1207
|
+
results.push({ index, success: true, sourceRef, ...result });
|
|
1208
|
+
} catch (error) {
|
|
1209
|
+
results.push({
|
|
1210
|
+
index,
|
|
1211
|
+
success: false,
|
|
1212
|
+
sourceRef,
|
|
1213
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return results;
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Confirm a day: every PROPOSED entry of yours that starts on that local
|
|
1221
|
+
* calendar day becomes CONFIRMED and the Actions' spent time moves. Human
|
|
1222
|
+
* only — the server refuses agent keys, so run this with personal
|
|
1223
|
+
* credentials. A day with nothing proposed returns `{ confirmed: 0 }`.
|
|
1224
|
+
*/
|
|
1225
|
+
async confirmDay(date, workspaceId) {
|
|
1226
|
+
return await this.client.timeEntry.confirmDay.mutate({
|
|
1227
|
+
date: startOfLocalDay(date),
|
|
1228
|
+
workspaceId
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* The day report for one local calendar day: entries joined to Action,
|
|
1233
|
+
* Ticket, Project and Product, attention / session / agent-run minutes,
|
|
1234
|
+
* the overlap-split roll-ups and the counts — exactly what the `/time` Day
|
|
1235
|
+
* tab and the Daily summary's Yesterday line read. Under an agent key the
|
|
1236
|
+
* report is the OWNER's day.
|
|
1237
|
+
*/
|
|
1238
|
+
async dayReport(date, workspaceId) {
|
|
1239
|
+
return await this.client.timeEntry.dayReport.query({
|
|
1240
|
+
date: startOfLocalDay(date),
|
|
1241
|
+
workspaceId
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* The caller's entries that touch one calendar day (local time), oldest
|
|
1246
|
+
* first, each with its `status`. Pass `YYYY-MM-DD` or a Date.
|
|
1247
|
+
*/
|
|
1248
|
+
async list(date, workspaceId) {
|
|
1249
|
+
const startDate = startOfLocalDay(date);
|
|
1250
|
+
const endDate = new Date(startDate.getTime() + 24 * 60 * 60 * 1e3);
|
|
1251
|
+
return await this.client.timeEntry.listByDateRange.query({
|
|
1252
|
+
startDate,
|
|
1253
|
+
endDate,
|
|
1254
|
+
workspaceId
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
|
|
1155
1259
|
// src/config.ts
|
|
1156
1260
|
import Conf from "conf";
|
|
1157
1261
|
var schema = {
|
|
@@ -1229,6 +1333,60 @@ function getConfigPath() {
|
|
|
1229
1333
|
return defaultStore.path;
|
|
1230
1334
|
}
|
|
1231
1335
|
|
|
1336
|
+
// src/segment.ts
|
|
1337
|
+
var DEFAULT_GAP_MINUTES = 30;
|
|
1338
|
+
var ROUND_MINUTES = 5;
|
|
1339
|
+
function roundDown(ms) {
|
|
1340
|
+
const grain = ROUND_MINUTES * 6e4;
|
|
1341
|
+
return new Date(Math.floor(ms / grain) * grain);
|
|
1342
|
+
}
|
|
1343
|
+
function roundUp(ms) {
|
|
1344
|
+
const grain = ROUND_MINUTES * 6e4;
|
|
1345
|
+
return new Date(Math.ceil(ms / grain) * grain);
|
|
1346
|
+
}
|
|
1347
|
+
function segmentConversation(messages, gapMinutes = DEFAULT_GAP_MINUTES) {
|
|
1348
|
+
const gapMs = gapMinutes * 6e4;
|
|
1349
|
+
const sorted = messages.map((m) => ({ at: new Date(m.at).getTime(), role: m.role })).filter((m) => !Number.isNaN(m.at)).sort((a, b) => a.at - b.at);
|
|
1350
|
+
const out = [];
|
|
1351
|
+
let seg = null;
|
|
1352
|
+
let run = null;
|
|
1353
|
+
const closeSegment = () => {
|
|
1354
|
+
if (seg) out.push({ start: roundDown(seg.start), end: roundUp(seg.end), humanTurns: seg.humanTurns });
|
|
1355
|
+
seg = null;
|
|
1356
|
+
};
|
|
1357
|
+
const resolveRun = () => {
|
|
1358
|
+
if (!run) return;
|
|
1359
|
+
if (run.end - run.start > gapMs) {
|
|
1360
|
+
closeSegment();
|
|
1361
|
+
out.push({ start: roundDown(run.start), end: roundUp(run.end), humanTurns: 0 });
|
|
1362
|
+
} else if (seg) {
|
|
1363
|
+
seg.end = Math.max(seg.end, run.end);
|
|
1364
|
+
}
|
|
1365
|
+
run = null;
|
|
1366
|
+
};
|
|
1367
|
+
for (const m of sorted) {
|
|
1368
|
+
if (m.role === "user") {
|
|
1369
|
+
resolveRun();
|
|
1370
|
+
if (seg && m.at - seg.lastUserAt > gapMs) closeSegment();
|
|
1371
|
+
if (!seg) seg = { start: m.at, end: m.at, humanTurns: 0, lastUserAt: m.at };
|
|
1372
|
+
seg.end = Math.max(seg.end, m.at);
|
|
1373
|
+
seg.lastUserAt = m.at;
|
|
1374
|
+
seg.humanTurns += 1;
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
if (run) {
|
|
1378
|
+
run.end = m.at;
|
|
1379
|
+
} else if (!seg || m.at - seg.lastUserAt > gapMs) {
|
|
1380
|
+
run = { start: m.at, end: m.at };
|
|
1381
|
+
} else {
|
|
1382
|
+
seg.end = Math.max(seg.end, m.at);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
resolveRun();
|
|
1386
|
+
closeSegment();
|
|
1387
|
+
return out;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1232
1390
|
// src/index.ts
|
|
1233
1391
|
var ExponentialClient = class {
|
|
1234
1392
|
constructor(config) {
|
|
@@ -1259,6 +1417,7 @@ var ExponentialClient = class {
|
|
|
1259
1417
|
this.requirements = new RequirementsApi(this.client);
|
|
1260
1418
|
this.scopes = new ScopesApi(this.client);
|
|
1261
1419
|
this.search = new SearchApi(this.client);
|
|
1420
|
+
this.time = new TimeApi(this.client);
|
|
1262
1421
|
}
|
|
1263
1422
|
client;
|
|
1264
1423
|
actions;
|
|
@@ -1287,16 +1446,22 @@ var ExponentialClient = class {
|
|
|
1287
1446
|
requirements;
|
|
1288
1447
|
scopes;
|
|
1289
1448
|
search;
|
|
1449
|
+
/** Time entries — the Daily worklog's write path (ADR-0061). */
|
|
1450
|
+
time;
|
|
1290
1451
|
};
|
|
1291
1452
|
export {
|
|
1453
|
+
DEFAULT_GAP_MINUTES,
|
|
1292
1454
|
ExponentialClient,
|
|
1455
|
+
ROUND_MINUTES,
|
|
1293
1456
|
TRPCClientError,
|
|
1457
|
+
TimeApi,
|
|
1294
1458
|
clearConfig,
|
|
1295
1459
|
createConfigStore,
|
|
1296
1460
|
getConfigPath,
|
|
1297
1461
|
isAuthenticated,
|
|
1298
1462
|
isTRPCError,
|
|
1299
1463
|
loadConfig,
|
|
1300
|
-
saveConfig
|
|
1464
|
+
saveConfig,
|
|
1465
|
+
segmentConversation
|
|
1301
1466
|
};
|
|
1302
1467
|
//# sourceMappingURL=index.js.map
|