@p4code/cli 0.2.30 → 0.2.32
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/bin.mjs +243 -59
- package/dist/client/assets/{DiffPanel-Bj9SAGnH.js → DiffPanel-yOCWQcwu.js} +3 -3
- package/dist/client/assets/{FilePreviewPanel-VP5WDapw.js → FilePreviewPanel-PGNwfXHq.js} +4 -4
- package/dist/client/assets/{PreviewPanel-B4WHLkbY.js → PreviewPanel-DuOntA1w.js} +2 -2
- package/dist/client/assets/{PullRequestCodeTab-DrzVpa0A.js → PullRequestCodeTab-Dz4XF0Nb.js} +2 -2
- package/dist/client/assets/arrow-right-BPchBceB.js +2 -0
- package/dist/client/assets/{fileCommentAnnotations-JxjT2DEs.js → fileCommentAnnotations-HbTI3JHj.js} +2 -2
- package/dist/client/assets/index-CfY-70_w.css +1 -0
- package/dist/client/assets/{index-DM-O3TKv.js → index-rdR8RpSW.js} +244 -234
- package/dist/client/assets/previewAssetResource-B_r-a_Fy.js +48 -0
- package/dist/client/assets/{renderFileChildren-BBXkpH2V.js → renderFileChildren-Da9sM-D2.js} +2 -2
- package/dist/client/assets/{toggle-group-L9VgzpO7.js → toggle-group-DzmkwXrU.js} +2 -2
- package/dist/client/index.html +3 -3
- package/package.json +1 -1
- package/dist/client/assets/arrow-right-4WRbFrGp.js +0 -2
- package/dist/client/assets/index-BOMxG-b0.css +0 -1
- package/dist/client/assets/previewAssetResource-DG52hZXj.js +0 -48
package/dist/bin.mjs
CHANGED
|
@@ -238,7 +238,7 @@ const make$90 = () => {
|
|
|
238
238
|
const layer$81 = Layer.sync(NetService, make$90);
|
|
239
239
|
//#endregion
|
|
240
240
|
//#region package.json
|
|
241
|
-
var version = "0.2.
|
|
241
|
+
var version = "0.2.32";
|
|
242
242
|
//#endregion
|
|
243
243
|
//#region src/config.ts
|
|
244
244
|
/**
|
|
@@ -7343,6 +7343,7 @@ const STATIC_KEYBINDING_COMMANDS = [
|
|
|
7343
7343
|
"terminal.close",
|
|
7344
7344
|
"rightPanel.toggle",
|
|
7345
7345
|
"board.toggle",
|
|
7346
|
+
"todos.toggle",
|
|
7346
7347
|
"diff.toggle",
|
|
7347
7348
|
"preview.toggle",
|
|
7348
7349
|
"preview.refresh",
|
|
@@ -7646,6 +7647,12 @@ const Task = Schema$1.Struct({
|
|
|
7646
7647
|
priority: TaskPriority,
|
|
7647
7648
|
assignee: Schema$1.NullOr(TrimmedNonEmptyString.check(Schema$1.isMaxLength(TASK_ASSIGNEE_MAX_LENGTH))),
|
|
7648
7649
|
labels: Schema$1.Array(TaskLabel).check(Schema$1.isMaxLength(TASK_LABELS_MAX_COUNT)),
|
|
7650
|
+
/**
|
|
7651
|
+
* When `status` last changed. Nullable-with-default for rows written by an
|
|
7652
|
+
* older server; current stores always stamp it. A dedicated timestamp keeps
|
|
7653
|
+
* completion and archive dates stable when title or labels change later.
|
|
7654
|
+
*/
|
|
7655
|
+
statusChangedAt: Schema$1.NullOr(IsoDateTime).pipe(Schema$1.withDecodingDefault(Effect.succeed(null))),
|
|
7649
7656
|
createdAt: IsoDateTime,
|
|
7650
7657
|
updatedAt: IsoDateTime
|
|
7651
7658
|
});
|
|
@@ -7712,6 +7719,7 @@ const HubTaskPutInput = Schema$1.Struct({
|
|
|
7712
7719
|
labels: LabelsField,
|
|
7713
7720
|
orderKey: Schema$1.NullOr(OrderKeyField),
|
|
7714
7721
|
createdAt: IsoDateTime,
|
|
7722
|
+
statusChangedAt: Schema$1.optional(IsoDateTime),
|
|
7715
7723
|
readableIdPrefix: Schema$1.optional(TrimmedNonEmptyString)
|
|
7716
7724
|
});
|
|
7717
7725
|
/**
|
|
@@ -8483,7 +8491,9 @@ const ServerProviderSkill = Schema$1.Struct({
|
|
|
8483
8491
|
scope: Schema$1.optional(TrimmedNonEmptyString),
|
|
8484
8492
|
enabled: Schema$1.Boolean,
|
|
8485
8493
|
displayName: Schema$1.optional(TrimmedNonEmptyString),
|
|
8486
|
-
shortDescription: Schema$1.optional(TrimmedNonEmptyString)
|
|
8494
|
+
shortDescription: Schema$1.optional(TrimmedNonEmptyString),
|
|
8495
|
+
/** Interaction mode P4Code selects when the user inserts this skill. */
|
|
8496
|
+
requiredInteractionMode: Schema$1.optional(ProviderInteractionMode)
|
|
8487
8497
|
});
|
|
8488
8498
|
/**
|
|
8489
8499
|
* Availability of a configured provider instance from the runtime's POV.
|
|
@@ -15574,6 +15584,14 @@ var _048_ProjectionThreadsPinned_default = Effect.gen(function* () {
|
|
|
15574
15584
|
`;
|
|
15575
15585
|
});
|
|
15576
15586
|
//#endregion
|
|
15587
|
+
//#region src/persistence/Migrations/049_TaskStatusChangedAt.ts
|
|
15588
|
+
/** Preserve status transition time independently from ordinary task edits. */
|
|
15589
|
+
var _049_TaskStatusChangedAt_default = Effect.gen(function* () {
|
|
15590
|
+
const sql = yield* SqlClient.SqlClient;
|
|
15591
|
+
yield* sql`ALTER TABLE tasks ADD COLUMN status_changed_at TEXT`;
|
|
15592
|
+
yield* sql`UPDATE tasks SET status_changed_at = updated_at WHERE status_changed_at IS NULL`;
|
|
15593
|
+
});
|
|
15594
|
+
//#endregion
|
|
15577
15595
|
//#region src/persistence/Migrations.ts
|
|
15578
15596
|
/**
|
|
15579
15597
|
* MigrationsLive - Migration runner with inline loader
|
|
@@ -15834,6 +15852,11 @@ const migrationEntries = [
|
|
|
15834
15852
|
48,
|
|
15835
15853
|
"ProjectionThreadsPinned",
|
|
15836
15854
|
_048_ProjectionThreadsPinned_default
|
|
15855
|
+
],
|
|
15856
|
+
[
|
|
15857
|
+
49,
|
|
15858
|
+
"TaskStatusChangedAt",
|
|
15859
|
+
_049_TaskStatusChangedAt_default
|
|
15837
15860
|
]
|
|
15838
15861
|
];
|
|
15839
15862
|
const makeMigrationLoader = (throughId) => Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
|
@@ -18471,6 +18494,7 @@ const TASK_COLUMNS$1 = `
|
|
|
18471
18494
|
assignee,
|
|
18472
18495
|
labels_json AS "labels",
|
|
18473
18496
|
order_key AS "orderKey",
|
|
18497
|
+
status_changed_at AS "statusChangedAt",
|
|
18474
18498
|
created_at AS "createdAt",
|
|
18475
18499
|
updated_at AS "updatedAt"
|
|
18476
18500
|
`;
|
|
@@ -18495,6 +18519,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
18495
18519
|
assignee,
|
|
18496
18520
|
labels_json,
|
|
18497
18521
|
order_key,
|
|
18522
|
+
status_changed_at,
|
|
18498
18523
|
created_at,
|
|
18499
18524
|
updated_at
|
|
18500
18525
|
)
|
|
@@ -18512,6 +18537,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
18512
18537
|
${row.assignee},
|
|
18513
18538
|
${JSON.stringify(row.labels)},
|
|
18514
18539
|
${row.orderKey},
|
|
18540
|
+
${row.statusChangedAt},
|
|
18515
18541
|
${row.createdAt},
|
|
18516
18542
|
${row.updatedAt}
|
|
18517
18543
|
)
|
|
@@ -18529,6 +18555,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
18529
18555
|
assignee = excluded.assignee,
|
|
18530
18556
|
labels_json = excluded.labels_json,
|
|
18531
18557
|
order_key = excluded.order_key,
|
|
18558
|
+
status_changed_at = excluded.status_changed_at,
|
|
18532
18559
|
created_at = excluded.created_at,
|
|
18533
18560
|
updated_at = excluded.updated_at
|
|
18534
18561
|
`
|
|
@@ -18628,6 +18655,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
18628
18655
|
...input.assignee !== void 0 ? { assignee: input.assignee } : {},
|
|
18629
18656
|
...input.labels !== void 0 ? { labels: input.labels } : {},
|
|
18630
18657
|
...input.orderKey !== void 0 ? { orderKey: input.orderKey } : {},
|
|
18658
|
+
statusChangedAt: input.status !== void 0 && input.status !== existing.value.status ? updatedAt : existing.value.statusChangedAt,
|
|
18631
18659
|
updatedAt
|
|
18632
18660
|
};
|
|
18633
18661
|
yield* upsertTaskRow(updated);
|
|
@@ -18667,6 +18695,7 @@ const makeTaskRepository = Effect.gen(function* () {
|
|
|
18667
18695
|
...input.patch.assignee !== void 0 ? { assignee: input.patch.assignee } : {},
|
|
18668
18696
|
...input.patch.labels !== void 0 ? { labels: input.patch.labels } : {},
|
|
18669
18697
|
...input.patch.orderKey !== void 0 ? { orderKey: input.patch.orderKey } : {},
|
|
18698
|
+
statusChangedAt: input.patch.status !== void 0 && input.patch.status !== existing.value.status ? updatedAt : existing.value.statusChangedAt,
|
|
18670
18699
|
updatedAt
|
|
18671
18700
|
};
|
|
18672
18701
|
yield* upsertTaskRow(updated);
|
|
@@ -18802,6 +18831,7 @@ const createTaskRoute = HttpRouter.add("POST", "/tasks", respondToHubFailures(Ef
|
|
|
18802
18831
|
assignee: input.assignee ?? null,
|
|
18803
18832
|
labels: input.labels ?? [],
|
|
18804
18833
|
orderKey: input.orderKey ?? null,
|
|
18834
|
+
statusChangedAt: timestamp,
|
|
18805
18835
|
createdAt: timestamp,
|
|
18806
18836
|
updatedAt: timestamp
|
|
18807
18837
|
};
|
|
@@ -18842,7 +18872,8 @@ const putTaskRoute = HttpRouter.add("PUT", "/tasks/:taskId", respondToHubFailure
|
|
|
18842
18872
|
priority: input.priority,
|
|
18843
18873
|
assignee: input.assignee,
|
|
18844
18874
|
labels: input.labels,
|
|
18845
|
-
orderKey: input.orderKey
|
|
18875
|
+
orderKey: input.orderKey,
|
|
18876
|
+
statusChangedAt: input.statusChangedAt ?? input.createdAt
|
|
18846
18877
|
};
|
|
18847
18878
|
const existing = yield* tasks.getById({ taskId });
|
|
18848
18879
|
if (Option.isNone(existing)) {
|
|
@@ -18857,6 +18888,7 @@ const putTaskRoute = HttpRouter.add("PUT", "/tasks/:taskId", respondToHubFailure
|
|
|
18857
18888
|
const replaced = {
|
|
18858
18889
|
...existing.value,
|
|
18859
18890
|
...fields,
|
|
18891
|
+
statusChangedAt: input.statusChangedAt ?? (input.status !== existing.value.status ? timestamp : existing.value.statusChangedAt ?? existing.value.updatedAt),
|
|
18860
18892
|
updatedAt: timestamp
|
|
18861
18893
|
};
|
|
18862
18894
|
yield* tasks.upsert(replaced);
|
|
@@ -19546,6 +19578,14 @@ var _013_FeedArticleCategories_default = Effect.gen(function* () {
|
|
|
19546
19578
|
yield* (yield* SqlClient.SqlClient)`ALTER TABLE feed_articles ADD COLUMN category TEXT`;
|
|
19547
19579
|
});
|
|
19548
19580
|
//#endregion
|
|
19581
|
+
//#region src/hub/Migrations/014_TaskStatusChangedAt.ts
|
|
19582
|
+
/** Keep completion and archive time stable across server replicas. */
|
|
19583
|
+
var _014_TaskStatusChangedAt_default = Effect.gen(function* () {
|
|
19584
|
+
const sql = yield* SqlClient.SqlClient;
|
|
19585
|
+
yield* sql`ALTER TABLE tasks ADD COLUMN status_changed_at TEXT`;
|
|
19586
|
+
yield* sql`UPDATE tasks SET status_changed_at = updated_at WHERE status_changed_at IS NULL`;
|
|
19587
|
+
});
|
|
19588
|
+
//#endregion
|
|
19549
19589
|
//#region src/hub/Migrations.ts
|
|
19550
19590
|
/**
|
|
19551
19591
|
* Hub migrations.
|
|
@@ -19621,6 +19661,11 @@ const hubMigrationEntries = [
|
|
|
19621
19661
|
13,
|
|
19622
19662
|
"FeedArticleCategories",
|
|
19623
19663
|
_013_FeedArticleCategories_default
|
|
19664
|
+
],
|
|
19665
|
+
[
|
|
19666
|
+
14,
|
|
19667
|
+
"TaskStatusChangedAt",
|
|
19668
|
+
_014_TaskStatusChangedAt_default
|
|
19624
19669
|
]
|
|
19625
19670
|
];
|
|
19626
19671
|
const hubMigrationLoader = Migrator.fromRecord(Object.fromEntries(hubMigrationEntries.map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
|
@@ -20216,11 +20261,13 @@ function parseMarkdownFrontmatter(contents) {
|
|
|
20216
20261
|
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
20217
20262
|
const description = typeof record.description === "string" ? record.description.trim() : "";
|
|
20218
20263
|
const disableModelInvocation = readFrontmatterBoolean(record["disable-model-invocation"]);
|
|
20264
|
+
const requiredInteractionMode = record["required-interaction-mode"] === "default" || record["required-interaction-mode"] === "plan" ? record["required-interaction-mode"] : void 0;
|
|
20219
20265
|
return {
|
|
20220
20266
|
kind: "parsed",
|
|
20221
20267
|
...name ? { name } : {},
|
|
20222
20268
|
...description ? { description } : {},
|
|
20223
|
-
...disableModelInvocation === void 0 ? {} : { disableModelInvocation }
|
|
20269
|
+
...disableModelInvocation === void 0 ? {} : { disableModelInvocation },
|
|
20270
|
+
...requiredInteractionMode === void 0 ? {} : { requiredInteractionMode }
|
|
20224
20271
|
};
|
|
20225
20272
|
}
|
|
20226
20273
|
/**
|
|
@@ -20304,7 +20351,8 @@ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config
|
|
|
20304
20351
|
path: skillPath
|
|
20305
20352
|
}, disabledSkills ?? []),
|
|
20306
20353
|
scope: root.scope,
|
|
20307
|
-
...frontmatter.kind === "parsed" && frontmatter.description ? { description: frontmatter.description } : {}
|
|
20354
|
+
...frontmatter.kind === "parsed" && frontmatter.description ? { description: frontmatter.description } : {},
|
|
20355
|
+
...frontmatter.kind === "parsed" && frontmatter.requiredInteractionMode ? { requiredInteractionMode: frontmatter.requiredInteractionMode } : {}
|
|
20308
20356
|
});
|
|
20309
20357
|
}
|
|
20310
20358
|
}
|
|
@@ -24034,6 +24082,7 @@ const ReadFromSequenceRequestSchema = Schema$1.Struct({
|
|
|
24034
24082
|
sequenceExclusive: NonNegativeInt,
|
|
24035
24083
|
limit: Schema$1.Number
|
|
24036
24084
|
});
|
|
24085
|
+
const ReadByCommandIdRequestSchema = Schema$1.Struct({ commandId: CommandId });
|
|
24037
24086
|
const DEFAULT_READ_FROM_SEQUENCE_LIMIT = 1e3;
|
|
24038
24087
|
const READ_PAGE_SIZE = 500;
|
|
24039
24088
|
function inferActorKind(event) {
|
|
@@ -24124,6 +24173,27 @@ const makeEventStore = Effect.gen(function* () {
|
|
|
24124
24173
|
WHERE sequence > ${request.sequenceExclusive}
|
|
24125
24174
|
ORDER BY sequence ASC
|
|
24126
24175
|
LIMIT ${request.limit}
|
|
24176
|
+
`
|
|
24177
|
+
});
|
|
24178
|
+
const readEventRowsByCommandId = SqlSchema.findAll({
|
|
24179
|
+
Request: ReadByCommandIdRequestSchema,
|
|
24180
|
+
Result: OrchestrationEventPersistedRowSchema,
|
|
24181
|
+
execute: ({ commandId }) => sql`
|
|
24182
|
+
SELECT
|
|
24183
|
+
sequence,
|
|
24184
|
+
event_id AS "eventId",
|
|
24185
|
+
event_type AS "type",
|
|
24186
|
+
aggregate_kind AS "aggregateKind",
|
|
24187
|
+
stream_id AS "aggregateId",
|
|
24188
|
+
occurred_at AS "occurredAt",
|
|
24189
|
+
command_id AS "commandId",
|
|
24190
|
+
causation_event_id AS "causationEventId",
|
|
24191
|
+
correlation_id AS "correlationId",
|
|
24192
|
+
payload_json AS "payload",
|
|
24193
|
+
metadata_json AS "metadata"
|
|
24194
|
+
FROM orchestration_events
|
|
24195
|
+
WHERE command_id = ${commandId}
|
|
24196
|
+
ORDER BY sequence ASC
|
|
24127
24197
|
`
|
|
24128
24198
|
});
|
|
24129
24199
|
const append = (event) => appendEventRow({
|
|
@@ -24153,8 +24223,10 @@ const makeEventStore = Effect.gen(function* () {
|
|
|
24153
24223
|
}));
|
|
24154
24224
|
return readPage(sequenceExclusive, normalizedLimit);
|
|
24155
24225
|
};
|
|
24226
|
+
const readByCommandId = (commandId) => readEventRowsByCommandId({ commandId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$4("OrchestrationEventStore.readByCommandId:query", "OrchestrationEventStore.readByCommandId:decodeRows")), Effect.flatMap((rows) => Effect.forEach(rows, (row) => decodeEvent(row).pipe(Effect.mapError(toPersistenceDecodeError("OrchestrationEventStore.readByCommandId:rowToEvent"))))));
|
|
24156
24227
|
return {
|
|
24157
24228
|
append,
|
|
24229
|
+
readByCommandId,
|
|
24158
24230
|
readFromSequence,
|
|
24159
24231
|
readAll: () => readFromSequence(0, Number.MAX_SAFE_INTEGER)
|
|
24160
24232
|
};
|
|
@@ -24855,6 +24927,9 @@ function projectEvent(model, event) {
|
|
|
24855
24927
|
//#endregion
|
|
24856
24928
|
//#region src/orchestration/decider.ts
|
|
24857
24929
|
const nowIso$8 = Effect.map(DateTime.now, DateTime.formatIso);
|
|
24930
|
+
function findActiveThreadPair(readModel, threadId) {
|
|
24931
|
+
return (readModel.threadPairs ?? []).find((pair) => pair.detachedAt === null && (pair.implementerThreadId === threadId || pair.watcherThreadId === threadId));
|
|
24932
|
+
}
|
|
24858
24933
|
const QUEUED_TURN_START_GRACE_MS = 120 * 1e3;
|
|
24859
24934
|
/**
|
|
24860
24935
|
* Blocked-on-you work derived from the thread's retained activities: an
|
|
@@ -25085,7 +25160,7 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
|
|
|
25085
25160
|
command,
|
|
25086
25161
|
threadId: command.threadId
|
|
25087
25162
|
});
|
|
25088
|
-
const activePair = (readModel
|
|
25163
|
+
const activePair = findActiveThreadPair(readModel, command.threadId);
|
|
25089
25164
|
if (activePair !== void 0) return yield* decideCommandSequence({
|
|
25090
25165
|
readModel,
|
|
25091
25166
|
commands: [{
|
|
@@ -25337,47 +25412,118 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
|
|
|
25337
25412
|
};
|
|
25338
25413
|
}
|
|
25339
25414
|
case "thread.archive": {
|
|
25340
|
-
|
|
25415
|
+
const activePair = findActiveThreadPair(readModel, command.threadId);
|
|
25416
|
+
if (activePair === void 0) {
|
|
25417
|
+
yield* requireThreadNotArchived({
|
|
25418
|
+
readModel,
|
|
25419
|
+
command,
|
|
25420
|
+
threadId: command.threadId
|
|
25421
|
+
});
|
|
25422
|
+
const occurredAt = yield* nowIso$8;
|
|
25423
|
+
return {
|
|
25424
|
+
...yield* withEventBase({
|
|
25425
|
+
aggregateKind: "thread",
|
|
25426
|
+
aggregateId: command.threadId,
|
|
25427
|
+
occurredAt,
|
|
25428
|
+
commandId: command.commandId
|
|
25429
|
+
}),
|
|
25430
|
+
type: "thread.archived",
|
|
25431
|
+
payload: {
|
|
25432
|
+
threadId: command.threadId,
|
|
25433
|
+
archivedAt: occurredAt,
|
|
25434
|
+
updatedAt: occurredAt
|
|
25435
|
+
}
|
|
25436
|
+
};
|
|
25437
|
+
}
|
|
25438
|
+
const occurredAt = yield* nowIso$8;
|
|
25439
|
+
const pairedThreads = [yield* requireThread({
|
|
25341
25440
|
readModel,
|
|
25342
25441
|
command,
|
|
25343
|
-
threadId:
|
|
25344
|
-
})
|
|
25345
|
-
const occurredAt = yield* nowIso$8;
|
|
25346
|
-
return {
|
|
25347
|
-
...yield* withEventBase({
|
|
25348
|
-
aggregateKind: "thread",
|
|
25349
|
-
aggregateId: command.threadId,
|
|
25350
|
-
occurredAt,
|
|
25351
|
-
commandId: command.commandId
|
|
25352
|
-
}),
|
|
25353
|
-
type: "thread.archived",
|
|
25354
|
-
payload: {
|
|
25355
|
-
threadId: command.threadId,
|
|
25356
|
-
archivedAt: occurredAt,
|
|
25357
|
-
updatedAt: occurredAt
|
|
25358
|
-
}
|
|
25359
|
-
};
|
|
25360
|
-
}
|
|
25361
|
-
case "thread.unarchive": {
|
|
25362
|
-
yield* requireThreadArchived({
|
|
25442
|
+
threadId: activePair.implementerThreadId
|
|
25443
|
+
}), yield* requireThread({
|
|
25363
25444
|
readModel,
|
|
25364
25445
|
command,
|
|
25365
|
-
threadId:
|
|
25366
|
-
});
|
|
25446
|
+
threadId: activePair.watcherThreadId
|
|
25447
|
+
})];
|
|
25448
|
+
const stopEvents = [];
|
|
25449
|
+
const archiveEvents = [];
|
|
25450
|
+
for (const thread of pairedThreads) {
|
|
25451
|
+
if (thread.session !== null && thread.session.status !== "stopped") stopEvents.push({
|
|
25452
|
+
...yield* withEventBase({
|
|
25453
|
+
aggregateKind: "thread",
|
|
25454
|
+
aggregateId: thread.id,
|
|
25455
|
+
occurredAt,
|
|
25456
|
+
commandId: command.commandId
|
|
25457
|
+
}),
|
|
25458
|
+
type: "thread.session-stop-requested",
|
|
25459
|
+
payload: {
|
|
25460
|
+
threadId: thread.id,
|
|
25461
|
+
createdAt: occurredAt
|
|
25462
|
+
}
|
|
25463
|
+
});
|
|
25464
|
+
archiveEvents.push({
|
|
25465
|
+
...yield* withEventBase({
|
|
25466
|
+
aggregateKind: "thread",
|
|
25467
|
+
aggregateId: thread.id,
|
|
25468
|
+
occurredAt,
|
|
25469
|
+
commandId: command.commandId
|
|
25470
|
+
}),
|
|
25471
|
+
type: "thread.archived",
|
|
25472
|
+
payload: {
|
|
25473
|
+
threadId: thread.id,
|
|
25474
|
+
archivedAt: thread.archivedAt ?? occurredAt,
|
|
25475
|
+
updatedAt: thread.archivedAt === null ? occurredAt : thread.updatedAt
|
|
25476
|
+
}
|
|
25477
|
+
});
|
|
25478
|
+
}
|
|
25479
|
+
return [...stopEvents, ...archiveEvents];
|
|
25480
|
+
}
|
|
25481
|
+
case "thread.unarchive": {
|
|
25482
|
+
const activePair = findActiveThreadPair(readModel, command.threadId);
|
|
25483
|
+
if (activePair === void 0) {
|
|
25484
|
+
yield* requireThreadArchived({
|
|
25485
|
+
readModel,
|
|
25486
|
+
command,
|
|
25487
|
+
threadId: command.threadId
|
|
25488
|
+
});
|
|
25489
|
+
const occurredAt = yield* nowIso$8;
|
|
25490
|
+
return {
|
|
25491
|
+
...yield* withEventBase({
|
|
25492
|
+
aggregateKind: "thread",
|
|
25493
|
+
aggregateId: command.threadId,
|
|
25494
|
+
occurredAt,
|
|
25495
|
+
commandId: command.commandId
|
|
25496
|
+
}),
|
|
25497
|
+
type: "thread.unarchived",
|
|
25498
|
+
payload: {
|
|
25499
|
+
threadId: command.threadId,
|
|
25500
|
+
updatedAt: occurredAt
|
|
25501
|
+
}
|
|
25502
|
+
};
|
|
25503
|
+
}
|
|
25367
25504
|
const occurredAt = yield* nowIso$8;
|
|
25368
|
-
|
|
25369
|
-
|
|
25370
|
-
|
|
25371
|
-
|
|
25372
|
-
|
|
25373
|
-
|
|
25374
|
-
})
|
|
25375
|
-
|
|
25376
|
-
|
|
25377
|
-
|
|
25378
|
-
|
|
25379
|
-
|
|
25380
|
-
|
|
25505
|
+
const events = [];
|
|
25506
|
+
for (const threadId of [activePair.implementerThreadId, activePair.watcherThreadId]) {
|
|
25507
|
+
const thread = yield* requireThread({
|
|
25508
|
+
readModel,
|
|
25509
|
+
command,
|
|
25510
|
+
threadId
|
|
25511
|
+
});
|
|
25512
|
+
events.push({
|
|
25513
|
+
...yield* withEventBase({
|
|
25514
|
+
aggregateKind: "thread",
|
|
25515
|
+
aggregateId: thread.id,
|
|
25516
|
+
occurredAt,
|
|
25517
|
+
commandId: command.commandId
|
|
25518
|
+
}),
|
|
25519
|
+
type: "thread.unarchived",
|
|
25520
|
+
payload: {
|
|
25521
|
+
threadId: thread.id,
|
|
25522
|
+
updatedAt: thread.archivedAt === null ? thread.updatedAt : occurredAt
|
|
25523
|
+
}
|
|
25524
|
+
});
|
|
25525
|
+
}
|
|
25526
|
+
return events;
|
|
25381
25527
|
}
|
|
25382
25528
|
case "thread.settle": {
|
|
25383
25529
|
const thread = yield* requireThreadNotArchived({
|
|
@@ -26194,7 +26340,13 @@ const makeOrchestrationEngine = Effect.gen(function* () {
|
|
|
26194
26340
|
});
|
|
26195
26341
|
const existingReceipt = yield* commandReceiptRepository.getByCommandId({ commandId: envelope.command.commandId });
|
|
26196
26342
|
if (Option.isSome(existingReceipt)) {
|
|
26197
|
-
if (existingReceipt.value.status === "accepted")
|
|
26343
|
+
if (existingReceipt.value.status === "accepted") {
|
|
26344
|
+
const events = yield* eventStore.readByCommandId(envelope.command.commandId);
|
|
26345
|
+
return {
|
|
26346
|
+
sequence: existingReceipt.value.resultSequence,
|
|
26347
|
+
events
|
|
26348
|
+
};
|
|
26349
|
+
}
|
|
26198
26350
|
return yield* new OrchestrationCommandPreviouslyRejectedError({
|
|
26199
26351
|
commandId: envelope.command.commandId,
|
|
26200
26352
|
detail: existingReceipt.value.error ?? "Previously rejected."
|
|
@@ -26246,7 +26398,10 @@ const makeOrchestrationEngine = Effect.gen(function* () {
|
|
|
26246
26398
|
ackEventType: event.type
|
|
26247
26399
|
})), Duration.millis(Math.max(0, (yield* Clock.currentTimeMillis) - envelope.startedAtMs)));
|
|
26248
26400
|
}
|
|
26249
|
-
return {
|
|
26401
|
+
return {
|
|
26402
|
+
sequence: committedCommand.lastSequence,
|
|
26403
|
+
events: committedCommand.committedEvents
|
|
26404
|
+
};
|
|
26250
26405
|
}).pipe(Effect.withSpan(`orchestration.command.${envelope.command.type}`))).pipe(Effect.flatMap((exit) => Effect.gen(function* () {
|
|
26251
26406
|
const outcome = Exit.isSuccess(exit) ? "success" : Cause.hasInterruptsOnly(exit.cause) ? "interrupt" : "failure";
|
|
26252
26407
|
yield* Metric.update(Metric.withAttributes(orchestrationCommandDuration, metricAttributes(baseMetricAttributes)), Duration.millis(Math.max(0, (yield* Clock.currentTimeMillis) - processingStartedAtMs)));
|
|
@@ -30902,8 +31057,9 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
|
|
|
30902
31057
|
listArchivedThreadRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getArchivedShellSnapshot:listThreads:query", "ProjectionSnapshotQuery.getArchivedShellSnapshot:listThreads:decodeRows"))),
|
|
30903
31058
|
listArchivedThreadSessionRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getArchivedShellSnapshot:listThreadSessions:query", "ProjectionSnapshotQuery.getArchivedShellSnapshot:listThreadSessions:decodeRows"))),
|
|
30904
31059
|
listArchivedLatestTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getArchivedShellSnapshot:listLatestTurns:query", "ProjectionSnapshotQuery.getArchivedShellSnapshot:listLatestTurns:decodeRows"))),
|
|
30905
|
-
listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getArchivedShellSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getArchivedShellSnapshot:listProjectionState:decodeRows")))
|
|
30906
|
-
|
|
31060
|
+
listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getArchivedShellSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getArchivedShellSnapshot:listProjectionState:decodeRows"))),
|
|
31061
|
+
listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getArchivedShellSnapshot:listThreadPairs:query", "ProjectionSnapshotQuery.getArchivedShellSnapshot:listThreadPairs:decodeRows")))
|
|
31062
|
+
])).pipe(Effect.flatMap(([projectRows, threadRows, sessionRows, latestTurnRows, stateRows, threadPairRows]) => Effect.gen(function* () {
|
|
30907
31063
|
let updatedAt = null;
|
|
30908
31064
|
for (const row of projectRows) updatedAt = maxIso(updatedAt, row.updatedAt);
|
|
30909
31065
|
for (const row of threadRows) updatedAt = maxIso(updatedAt, row.updatedAt);
|
|
@@ -30918,6 +31074,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
|
|
|
30918
31074
|
const repositoryIdentities = yield* resolveRepositoryIdentitiesForProjects(projectRows.filter((row) => activeProjectIds.has(row.projectId)));
|
|
30919
31075
|
const latestTurnByThread = new Map(latestTurnRows.map((row) => [row.threadId, mapLatestTurn(row)]));
|
|
30920
31076
|
const sessionByThread = new Map(sessionRows.map((row) => [row.threadId, mapSessionRow(row)]));
|
|
31077
|
+
const archivedThreadIds = new Set(threadRows.map((row) => row.threadId));
|
|
30921
31078
|
const snapshot = {
|
|
30922
31079
|
snapshotSequence: computeSnapshotSequence(stateRows),
|
|
30923
31080
|
projects: Arr.filterMap(projectRows, (row) => row.deletedAt === null && activeProjectIds.has(row.projectId) ? Result.succeed(mapProjectShellRow(row, repositoryIdentities.get(row.projectId) ?? null)) : Result.failVoid),
|
|
@@ -30951,6 +31108,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
|
|
|
30951
31108
|
hasBackgroundTasks: row.backgroundTaskCount > 0,
|
|
30952
31109
|
scheduledWakeAt: row.scheduledWakeAt
|
|
30953
31110
|
})),
|
|
31111
|
+
threadPairs: threadPairRows.filter((pair) => pair.detachedAt === null && (archivedThreadIds.has(pair.implementerThreadId) || archivedThreadIds.has(pair.watcherThreadId))),
|
|
30954
31112
|
updatedAt: updatedAt ?? "1970-01-01T00:00:00.000Z"
|
|
30955
31113
|
};
|
|
30956
31114
|
return yield* decodeShellSnapshot(snapshot).pipe(Effect.mapError(toPersistenceDecodeError("ProjectionSnapshotQuery.getArchivedShellSnapshot:decodeShellSnapshot")));
|
|
@@ -31255,6 +31413,10 @@ const DEFAULT_KEYBINDINGS = [
|
|
|
31255
31413
|
key: "mod+shift+b",
|
|
31256
31414
|
command: "board.toggle"
|
|
31257
31415
|
},
|
|
31416
|
+
{
|
|
31417
|
+
key: "mod+alt+t",
|
|
31418
|
+
command: "todos.toggle"
|
|
31419
|
+
},
|
|
31258
31420
|
{
|
|
31259
31421
|
key: "mod+d",
|
|
31260
31422
|
command: "terminal.split",
|
|
@@ -41229,6 +41391,7 @@ const taskFromLinearIssue = (issue, link = EMPTY_LINEAR_TASK_LINK) => {
|
|
|
41229
41391
|
priority: priorityFromLinear(issue["priority"]),
|
|
41230
41392
|
assignee: personName(issue["assignee"]),
|
|
41231
41393
|
labels: labelNames(issue["labels"]),
|
|
41394
|
+
statusChangedAt: updatedAt ?? createdAt ?? "1970-01-01T00:00:00.000Z",
|
|
41232
41395
|
createdAt: createdAt ?? updatedAt ?? "1970-01-01T00:00:00.000Z",
|
|
41233
41396
|
updatedAt: updatedAt ?? createdAt ?? "1970-01-01T00:00:00.000Z"
|
|
41234
41397
|
};
|
|
@@ -41620,6 +41783,7 @@ const makeHubTaskClient = Effect.gen(function* () {
|
|
|
41620
41783
|
labels: row.labels,
|
|
41621
41784
|
orderKey: row.orderKey,
|
|
41622
41785
|
createdAt: row.createdAt,
|
|
41786
|
+
statusChangedAt: row.statusChangedAt ?? row.updatedAt,
|
|
41623
41787
|
readableIdPrefix
|
|
41624
41788
|
}));
|
|
41625
41789
|
if (response.status !== 200 && response.status !== 201) return yield* hubUnavailable("put", `status ${response.status}`);
|
|
@@ -41691,6 +41855,7 @@ const TASK_COLUMNS = `
|
|
|
41691
41855
|
assignee,
|
|
41692
41856
|
labels_json AS "labels",
|
|
41693
41857
|
order_key AS "orderKey",
|
|
41858
|
+
status_changed_at AS "statusChangedAt",
|
|
41694
41859
|
created_at AS "createdAt",
|
|
41695
41860
|
updated_at AS "updatedAt"
|
|
41696
41861
|
`;
|
|
@@ -42070,6 +42235,7 @@ const buildTaskRow = (input, taskId, timestamp, repositoryKey = null) => ({
|
|
|
42070
42235
|
assignee: input.assignee ?? null,
|
|
42071
42236
|
labels: input.labels ?? [],
|
|
42072
42237
|
orderKey: null,
|
|
42238
|
+
statusChangedAt: timestamp,
|
|
42073
42239
|
createdAt: timestamp,
|
|
42074
42240
|
updatedAt: timestamp
|
|
42075
42241
|
});
|
|
@@ -62302,7 +62468,12 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
62302
62468
|
})), Effect.orElseSucceed(() => false)) : false;
|
|
62303
62469
|
const result = yield* dispatchNormalizedCommand(normalizedCommand);
|
|
62304
62470
|
if (normalizedCommand.type === "thread.archive") {
|
|
62305
|
-
|
|
62471
|
+
const archivedThreadIds = result.events?.filter((event) => event.type === "thread.archived").map((event) => event.payload.threadId);
|
|
62472
|
+
if (archivedThreadIds === void 0 || archivedThreadIds.length === 0) return yield* new OrchestrationDispatchCommandError({ message: "Archive command completed without authoritative archive events." });
|
|
62473
|
+
const uniqueArchivedThreadIds = Array.from(new Set(archivedThreadIds));
|
|
62474
|
+
const pairedArchive = uniqueArchivedThreadIds.length > 1;
|
|
62475
|
+
if (!uniqueArchivedThreadIds.includes(normalizedCommand.threadId)) return yield* new OrchestrationDispatchCommandError({ message: "Archive command result did not include the requested thread." });
|
|
62476
|
+
if (shouldStopSessionAfterArchive && !pairedArchive) yield* Effect.gen(function* () {
|
|
62306
62477
|
const stopCommand = yield* normalizeDispatchCommand({
|
|
62307
62478
|
type: "thread.session.stop",
|
|
62308
62479
|
commandId: CommandId.make(`session-stop-for-archive:${normalizedCommand.commandId}`),
|
|
@@ -62314,12 +62485,12 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
62314
62485
|
threadId: normalizedCommand.threadId,
|
|
62315
62486
|
cause
|
|
62316
62487
|
})));
|
|
62317
|
-
yield* terminalManager.close({ threadId
|
|
62318
|
-
threadId
|
|
62488
|
+
yield* Effect.forEach(uniqueArchivedThreadIds, (threadId) => terminalManager.close({ threadId }).pipe(Effect.catch((error) => Effect.logWarning("failed to close thread terminals after archive", {
|
|
62489
|
+
threadId,
|
|
62319
62490
|
error: error.message
|
|
62320
|
-
})));
|
|
62491
|
+
}))), { discard: true });
|
|
62321
62492
|
}
|
|
62322
|
-
return result;
|
|
62493
|
+
return { sequence: result.sequence };
|
|
62323
62494
|
}).pipe(Effect.mapError((cause) => isOrchestrationDispatchCommandError(cause) ? cause : new OrchestrationDispatchCommandError({
|
|
62324
62495
|
message: "Failed to dispatch orchestration command",
|
|
62325
62496
|
cause
|
|
@@ -87875,6 +88046,17 @@ function parseCodexSkillsListResponse(response, cwd) {
|
|
|
87875
88046
|
return parsedSkill;
|
|
87876
88047
|
});
|
|
87877
88048
|
}
|
|
88049
|
+
/** Codex omits unknown SKILL.md frontmatter, so enrich its snapshot from each advertised path. */
|
|
88050
|
+
const enrichCodexSkillsWithFrontmatter = Effect.fnUntraced(function* (skills) {
|
|
88051
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
88052
|
+
return yield* Effect.forEach(skills, (skill) => fileSystem.readFileString(skill.path).pipe(Effect.map((contents) => {
|
|
88053
|
+
const frontmatter = parseMarkdownFrontmatter(contents);
|
|
88054
|
+
return frontmatter.kind === "parsed" && frontmatter.requiredInteractionMode ? {
|
|
88055
|
+
...skill,
|
|
88056
|
+
requiredInteractionMode: frontmatter.requiredInteractionMode
|
|
88057
|
+
} : skill;
|
|
88058
|
+
}), Effect.orElseSucceed(() => skill)), { concurrency: "unbounded" });
|
|
88059
|
+
});
|
|
87878
88060
|
const requestAllCodexModels = Effect.fn("requestAllCodexModels")(function* (client) {
|
|
87879
88061
|
const models = [];
|
|
87880
88062
|
let cursor = void 0;
|
|
@@ -87937,11 +88119,12 @@ const probeCodexAppServerProvider = Effect.fn("probeCodexAppServerProvider")(fun
|
|
|
87937
88119
|
skills: []
|
|
87938
88120
|
};
|
|
87939
88121
|
const [skillsResponse, models] = yield* Effect.all([client.request("skills/list", { cwds: [input.cwd] }), requestAllCodexModels(client)], { concurrency: "unbounded" });
|
|
88122
|
+
const skills = yield* enrichCodexSkillsWithFrontmatter(parseCodexSkillsListResponse(skillsResponse, input.cwd));
|
|
87940
88123
|
return {
|
|
87941
88124
|
account: accountResponse,
|
|
87942
88125
|
version,
|
|
87943
88126
|
models: applyPreferredCodexDefaultModel(appendCustomCodexModels(models, input.customModels ?? [])),
|
|
87944
|
-
skills
|
|
88127
|
+
skills
|
|
87945
88128
|
};
|
|
87946
88129
|
});
|
|
87947
88130
|
const emptyCodexModelsFromSettings = (codexSettings) => {
|
|
@@ -90582,6 +90765,7 @@ const CodexDriver = {
|
|
|
90582
90765
|
defaultConfig: () => decodeCodexSettings({}),
|
|
90583
90766
|
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) => Effect.gen(function* () {
|
|
90584
90767
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
90768
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
90585
90769
|
const httpClient = yield* HttpClient.HttpClient;
|
|
90586
90770
|
const serverSettings = yield* ServerSettingsService;
|
|
90587
90771
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -90616,7 +90800,7 @@ const CodexDriver = {
|
|
|
90616
90800
|
...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
|
|
90617
90801
|
});
|
|
90618
90802
|
const textGeneration = yield* makeCodexTextGeneration(effectiveConfig, processEnv);
|
|
90619
|
-
const checkProvider = checkCodexProviderStatus(effectiveConfig, void 0, processEnv).pipe(Effect.map(stampIdentity), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
|
|
90803
|
+
const checkProvider = checkCodexProviderStatus(effectiveConfig, void 0, processEnv).pipe(Effect.map(stampIdentity), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(FileSystem.FileSystem, fileSystem));
|
|
90620
90804
|
const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
|
|
90621
90805
|
const snapshot = yield* makeManagedServerProvider({
|
|
90622
90806
|
maintenanceCapabilities,
|
|
@@ -105237,18 +105421,18 @@ const ProviderRuntimeIngestionLive = Layer.effect(ProviderRuntimeIngestionServic
|
|
|
105237
105421
|
* @module provider/userInvokedSkills
|
|
105238
105422
|
*/
|
|
105239
105423
|
/**
|
|
105240
|
-
* A leading `/name`, with whatever followed it.
|
|
105424
|
+
* A leading `/name` or `$name`, with whatever followed it.
|
|
105241
105425
|
*
|
|
105242
|
-
* Anchored at the start: a
|
|
105243
|
-
*
|
|
105426
|
+
* Anchored at the start: a marker somewhere inside a sentence can be a path,
|
|
105427
|
+
* date, currency, or prose, and treating it as a command would rewrite ordinary
|
|
105244
105428
|
* messages. The name pattern matches what a skill directory can be called,
|
|
105245
105429
|
* including the `plugin:skill` form.
|
|
105246
105430
|
*/
|
|
105247
|
-
const
|
|
105431
|
+
const SKILL_INVOCATION = /^[/$]([A-Za-z0-9][A-Za-z0-9_:-]*)[ \t]*([\s\S]*)$/;
|
|
105248
105432
|
/** `SKILL.md` is the only file a skill is required to have. */
|
|
105249
105433
|
const SKILL_FILENAME = "SKILL.md";
|
|
105250
105434
|
const parseSlashInvocation = (text) => {
|
|
105251
|
-
const match =
|
|
105435
|
+
const match = SKILL_INVOCATION.exec(text.trim());
|
|
105252
105436
|
const name = match?.[1];
|
|
105253
105437
|
if (name === void 0) return void 0;
|
|
105254
105438
|
return {
|
|
@@ -105532,7 +105716,7 @@ const make$3 = Effect.gen(function* () {
|
|
|
105532
105716
|
return yield* projectionSnapshotQuery.getProjectShellById(projectId).pipe(Effect.map(Option.getOrUndefined));
|
|
105533
105717
|
});
|
|
105534
105718
|
/**
|
|
105535
|
-
* Where a typed `/name` is looked up: the user's skills, then the
|
|
105719
|
+
* Where a typed `/name` or `$name` is looked up: the user's skills, then the
|
|
105536
105720
|
* workspace's.
|
|
105537
105721
|
*
|
|
105538
105722
|
* Project last so it wins, matching the CLI's most-specific-wins resolution.
|