@openspecui/core 5.0.0 → 6.0.0-beta.1
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/cli-projection-CBvIiy5p.d.mts +789 -0
- package/dist/cli-projection-vO3-FJg5.mjs +161 -0
- package/dist/cli-projection.d.mts +6 -0
- package/dist/cli-projection.mjs +4 -0
- package/dist/command-result-CuWzPRAT.d.mts +8477 -0
- package/dist/common-D8YUK9dA.mjs +57 -0
- package/dist/dashboard-display.d.mts +22 -1
- package/dist/dashboard-display.mjs +42 -1
- package/dist/dashboard-summary-transport-CYBuU4iT.mjs +189 -0
- package/dist/dashboard-summary-transport-Dskh3E9-.d.mts +67407 -0
- package/dist/dashboard-summary-transport.d.mts +25 -0
- package/dist/dashboard-summary-transport.mjs +6 -0
- package/dist/{document-translation-D4YK18I3.mjs → document-translation-CeJFGMoy.mjs} +1 -1
- package/dist/{document-translation-7R8cf8_B.d.mts → document-translation-D50BnvVh.d.mts} +2 -2
- package/dist/document-translation.d.mts +1 -1
- package/dist/document-translation.mjs +2 -2
- package/dist/{hosted-app-CzMRiEgY.mjs → hosted-app-BPU4OR41.mjs} +31 -9
- package/dist/hosted-app.d.mts +25 -2
- package/dist/hosted-app.mjs +7 -2
- package/dist/hosted-contract-CcRnb51e.mjs +234 -0
- package/dist/hosted-contract.d.mts +25 -0
- package/dist/hosted-contract.mjs +7 -0
- package/dist/index.d.mts +25 -2686
- package/dist/index.mjs +2114 -1098
- package/dist/{local-download-profiles-caa4PECd.d.mts → local-download-profiles-bYSSKmtx.d.mts} +1 -1
- package/dist/local-download-profiles.d.mts +2 -2
- package/dist/local-download-profiles.mjs +1 -1
- package/dist/markdown-facts.d.mts +1 -1
- package/dist/markdown-facts.mjs +1 -1
- package/dist/{markdown-reading-CgXuXp6s.d.mts → markdown-reading-LUdqfbxH.d.mts} +1 -1
- package/dist/{markdown-reading-DdcB7run.mjs → markdown-reading-mG4OAbDO.mjs} +1 -1
- package/dist/markdown-reading.d.mts +2 -2
- package/dist/markdown-reading.mjs +2 -2
- package/dist/{notifications-DZeOl4HV.d.mts → notifications-Ak6LdCaL.d.mts} +42 -16
- package/dist/{notifications-AKAcmeKT.mjs → notifications-C2bxAzX_.mjs} +13 -2
- package/dist/notifications.d.mts +2 -2
- package/dist/notifications.mjs +3 -3
- package/dist/{openspec-annotations-CeXd0JIZ.d.mts → openspec-annotations-C58Aoi-V.d.mts} +2 -2
- package/dist/{openspec-annotations-D_6Pz7k4.mjs → openspec-annotations-DCfqBMal.mjs} +2 -2
- package/dist/openspec-annotations.d.mts +3 -3
- package/dist/openspec-annotations.mjs +3 -3
- package/dist/openspec-compat.d.mts +18 -11
- package/dist/openspec-compat.mjs +20 -13
- package/dist/{openspec-projection-B8s-KWQ7.mjs → openspec-projection-DCgToo0Q.mjs} +2 -2
- package/dist/{openspec-projection-B0ch1rZw.d.mts → openspec-projection-DU7RFRyA.d.mts} +3 -3
- package/dist/openspec-projection.d.mts +5 -5
- package/dist/openspec-projection.mjs +4 -4
- package/dist/opsx-display-path.d.mts +1 -1
- package/dist/opsx-display-path.mjs +1 -1
- package/dist/{opsx-entity-DZyl-uhQ.d.mts → opsx-entity-6PnbYZZp.d.mts} +2 -2
- package/dist/opsx-entity.d.mts +7 -3
- package/dist/opsx-entity.mjs +1 -1
- package/dist/{opsx-schema-detail-CS0tWa9v.d.mts → opsx-schema-detail-CiqCYl2F.d.mts} +2 -2
- package/dist/opsx-schema-detail.d.mts +8 -4
- package/dist/opsx-schema-detail.mjs +1 -1
- package/dist/opsx-types-Fs0tRnL2.d.mts +3642 -0
- package/dist/opsx-workflows-BvnJqjfL.d.mts +36 -0
- package/dist/opsx-workflows-Ccc6U7IR.mjs +89 -0
- package/dist/opsx-workflows.d.mts +2 -0
- package/dist/opsx-workflows.mjs +3 -0
- package/dist/planning-cli-projection-DIRxeq2H.mjs +421 -0
- package/dist/planning-cli-projection.d.mts +25 -0
- package/dist/planning-cli-projection.mjs +9 -0
- package/dist/schemas-BFroDdOC.mjs +287 -0
- package/dist/{schemas-D01aQnV4.d.mts → schemas-D-6yi_I-.d.mts} +524 -78
- package/dist/{sounds-kgDn4x8v.d.mts → sounds-C24SzEHX.d.mts} +4 -4
- package/dist/sounds.d.mts +1 -1
- package/dist/sounds.mjs +1 -1
- package/dist/spec-catalog-ZGuiZ4CE.mjs +901 -0
- package/dist/spec-catalog.d.mts +25 -0
- package/dist/spec-catalog.mjs +6 -0
- package/dist/store-mutation-protocol-3TzQ6ete.d.mts +727 -0
- package/dist/store-mutation-protocol-CSwD-xPO.mjs +63 -0
- package/dist/store-mutation-protocol.d.mts +2 -0
- package/dist/store-mutation-protocol.mjs +4 -0
- package/dist/{store-types-BiE-Ey--.d.mts → store-types-CmDVyObq.d.mts} +22 -12
- package/dist/{store-types-Cu41QSww.mjs → store-types-DlX1REBg.mjs} +39 -18
- package/dist/store-types.d.mts +6 -2
- package/dist/store-types.mjs +2 -2
- package/dist/task-progress-B_IWVXjA.mjs +216 -0
- package/dist/task-progress.d.mts +7 -4
- package/dist/task-progress.mjs +3 -3
- package/dist/{terminal-audio-CsuGTNV-.d.mts → terminal-audio-Rj1pLeSw.d.mts} +1 -1
- package/dist/{terminal-audio-TBoU2jSK.mjs → terminal-audio-d6KItUeJ.mjs} +1 -1
- package/dist/terminal-audio.d.mts +2 -2
- package/dist/terminal-audio.mjs +2 -2
- package/dist/terminal-control.d.mts +2 -2
- package/dist/terminal-control.mjs +1 -1
- package/dist/{terminal-invocation-BlFwKpIc.d.mts → terminal-invocation-G19ieMZy.d.mts} +212 -93
- package/dist/terminal-invocation.d.mts +1 -1
- package/dist/terminal-invocation.mjs +1 -1
- package/dist/terminal-theme.d.mts +1 -1
- package/dist/terminal-theme.mjs +1 -1
- package/dist/translation-language-pair.d.mts +1 -1
- package/dist/translation-language-pair.mjs +1 -1
- package/dist/{translator-BErXgQxx.d.mts → translator-CNmE1fAm.d.mts} +132 -132
- package/dist/translator.d.mts +1 -1
- package/dist/translator.mjs +1 -1
- package/package.json +55 -7
- package/dist/hosted-app-DHs94gIR.d.mts +0 -43
- package/dist/opsx-types-Dnb06uff.d.mts +0 -402
- package/dist/task-progress-C1TGMbIR.d.mts +0 -24
- package/dist/task-progress-DhHYHnTv.mjs +0 -70
- /package/dist/{local-download-profiles-kpNEcdF_.mjs → local-download-profiles-odzOdf96.mjs} +0 -0
- /package/dist/{markdown-facts-BBCTe_qq.mjs → markdown-facts-BUqLvFRf.mjs} +0 -0
- /package/dist/{markdown-facts-Dk7FKaaT.d.mts → markdown-facts-CCw3QdbM.d.mts} +0 -0
- /package/dist/{opsx-display-path-CUCOrHcM.mjs → opsx-display-path-D13XV20v.mjs} +0 -0
- /package/dist/{opsx-display-path-cIMKa1aw.d.mts → opsx-display-path-RXS5JTbV.d.mts} +0 -0
- /package/dist/{opsx-entity-c7m5CbgU.mjs → opsx-entity-Cn_Zu1J3.mjs} +0 -0
- /package/dist/{opsx-schema-detail-BH82X6aU.mjs → opsx-schema-detail-Beis4Ba2.mjs} +0 -0
- /package/dist/{sounds-CB3ubSnj.mjs → sounds-NXwveBqq.mjs} +0 -0
- /package/dist/{terminal-control-VpTuh17B.mjs → terminal-control-BSAlOTs8.mjs} +0 -0
- /package/dist/{terminal-invocation-C2MCNBhK.mjs → terminal-invocation-0p-j2eSP.mjs} +0 -0
- /package/dist/{terminal-theme-cevliJw2.mjs → terminal-theme-B8iRttTR.mjs} +0 -0
- /package/dist/{terminal-theme-hvQjTsNh.d.mts → terminal-theme-m3MSGJ7U.d.mts} +0 -0
- /package/dist/{translation-language-pair-DZ_WNp_M.mjs → translation-language-pair-Bbhk-LAC.mjs} +0 -0
- /package/dist/{translation-language-pair-DmaOfHqD.d.mts → translation-language-pair-C18GPATW.d.mts} +0 -0
- /package/dist/{translator-DbUT1Ayn.mjs → translator-Cjtv4tya.mjs} +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/cli-contracts/common.ts
|
|
4
|
+
/**
|
|
5
|
+
* Orthogonal intents (created 2026-07-15 Asia/Shanghai):
|
|
6
|
+
* 1. Model OpenSpec CLI diagnostics without reinterpreting their meaning.
|
|
7
|
+
* 2. Preserve root selection provenance exactly as emitted by the CLI.
|
|
8
|
+
* 3. Preserve direct Reference indexes and their upstream health evidence.
|
|
9
|
+
*
|
|
10
|
+
* Original request (2026-07-15): "CLI JSON、stderr、诊断、resolved paths、root provenance、exit status 必须完整保留。"
|
|
11
|
+
*/
|
|
12
|
+
/** Upstream diagnostic emitted in a CLI JSON status array. */
|
|
13
|
+
const CliDiagnosticSchema = z.object({
|
|
14
|
+
severity: z.enum([
|
|
15
|
+
"error",
|
|
16
|
+
"warning",
|
|
17
|
+
"info"
|
|
18
|
+
]),
|
|
19
|
+
code: z.string(),
|
|
20
|
+
message: z.string(),
|
|
21
|
+
target: z.string().optional(),
|
|
22
|
+
fix: z.string().optional()
|
|
23
|
+
}).passthrough();
|
|
24
|
+
/** Upstream provenance for the CLI-selected planning root. */
|
|
25
|
+
const CliRootSourceSchema = z.enum([
|
|
26
|
+
"store",
|
|
27
|
+
"declared",
|
|
28
|
+
"nearest",
|
|
29
|
+
"implicit"
|
|
30
|
+
]);
|
|
31
|
+
/** CLI-selected planning root with upstream selection provenance. */
|
|
32
|
+
const CliRootSchema = z.object({
|
|
33
|
+
path: z.string(),
|
|
34
|
+
source: CliRootSourceSchema,
|
|
35
|
+
store_id: z.string().optional()
|
|
36
|
+
}).passthrough();
|
|
37
|
+
/** Lightweight Spec fact exposed by a direct Reference index. */
|
|
38
|
+
const CliReferenceSpecSchema = z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
summary: z.string()
|
|
41
|
+
}).passthrough();
|
|
42
|
+
/** Health-only direct Reference entry emitted by OpenSpec Doctor. */
|
|
43
|
+
const CliDoctorReferenceEntrySchema = z.object({
|
|
44
|
+
store_id: z.string(),
|
|
45
|
+
root: z.string().optional(),
|
|
46
|
+
status: z.array(CliDiagnosticSchema)
|
|
47
|
+
}).passthrough();
|
|
48
|
+
/** Spec-bearing direct Reference index emitted by workflow Instructions. */
|
|
49
|
+
const CliReferenceIndexEntrySchema = CliDoctorReferenceEntrySchema.extend({
|
|
50
|
+
specs: z.array(CliReferenceSpecSchema).optional(),
|
|
51
|
+
fetch: z.string().optional()
|
|
52
|
+
}).passthrough();
|
|
53
|
+
/** JSON failure payload whose truth is carried entirely by upstream diagnostics. */
|
|
54
|
+
const CliDiagnosticFailureSchema = z.object({ status: z.array(CliDiagnosticSchema).min(1) }).passthrough();
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { CliRootSchema as a, CliReferenceIndexEntrySchema as i, CliDiagnosticSchema as n, CliRootSourceSchema as o, CliDoctorReferenceEntrySchema as r, CliDiagnosticFailureSchema as t };
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
//#region src/dashboard-display.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Orthogonal intents (updated 2026-07-28 Asia/Shanghai):
|
|
4
|
+
* 1. Select bounded Dashboard rows with deterministic ordering.
|
|
5
|
+
* 2. Resolve archive dates identically across Server and browser/static consumers.
|
|
6
|
+
* 3. Apply the objective bounded archive-range policy without owning UI state.
|
|
7
|
+
*
|
|
8
|
+
* Original request (2026-07-28): replace Dashboard Workflow Progress with ReadonlyKanban.
|
|
9
|
+
*/
|
|
2
10
|
declare const DASHBOARD_RECENT_LIST_LIMIT = 10;
|
|
11
|
+
type DashboardArchiveRange = '7d' | '30d' | '90d' | 'all';
|
|
12
|
+
interface DashboardArchiveTimeSource {
|
|
13
|
+
id: string;
|
|
14
|
+
updatedAt: number;
|
|
15
|
+
}
|
|
16
|
+
/** Parse a valid UTC calendar date from an archive id prefix. */
|
|
17
|
+
declare function parseDatedArchiveIdTimestamp(id: string): number | null;
|
|
18
|
+
/** Resolve the archive timestamp from its dated id, then its physical update time. */
|
|
19
|
+
declare function resolveArchiveTimestamp(archive: DashboardArchiveTimeSource): number;
|
|
20
|
+
/** Test whether an archive belongs to a user-selected trailing range. */
|
|
21
|
+
declare function isArchiveInRange(archive: DashboardArchiveTimeSource, range: DashboardArchiveRange, now?: number): boolean;
|
|
3
22
|
interface DashboardRecentListItem {
|
|
4
23
|
id: string;
|
|
5
24
|
updatedAt: number;
|
|
@@ -7,5 +26,7 @@ interface DashboardRecentListItem {
|
|
|
7
26
|
declare function compareDashboardItemsByUpdatedAt<T extends DashboardRecentListItem>(left: T, right: T): number;
|
|
8
27
|
declare function sortDashboardItemsByUpdatedAt<T extends DashboardRecentListItem>(items: readonly T[]): T[];
|
|
9
28
|
declare function selectRecentDashboardItems<T extends DashboardRecentListItem>(items: readonly T[], limit?: number): T[];
|
|
29
|
+
/** Select recent archives by objective archive time rather than incidental directory mtime. */
|
|
30
|
+
declare function selectRecentDashboardArchives<T extends DashboardArchiveTimeSource>(items: readonly T[], limit?: number): T[];
|
|
10
31
|
//#endregion
|
|
11
|
-
export { DASHBOARD_RECENT_LIST_LIMIT, DashboardRecentListItem, compareDashboardItemsByUpdatedAt, selectRecentDashboardItems, sortDashboardItemsByUpdatedAt };
|
|
32
|
+
export { DASHBOARD_RECENT_LIST_LIMIT, DashboardArchiveRange, DashboardArchiveTimeSource, DashboardRecentListItem, compareDashboardItemsByUpdatedAt, isArchiveInRange, parseDatedArchiveIdTimestamp, resolveArchiveTimestamp, selectRecentDashboardArchives, selectRecentDashboardItems, sortDashboardItemsByUpdatedAt };
|
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
//#region src/dashboard-display.ts
|
|
2
|
+
/**
|
|
3
|
+
* Orthogonal intents (updated 2026-07-28 Asia/Shanghai):
|
|
4
|
+
* 1. Select bounded Dashboard rows with deterministic ordering.
|
|
5
|
+
* 2. Resolve archive dates identically across Server and browser/static consumers.
|
|
6
|
+
* 3. Apply the objective bounded archive-range policy without owning UI state.
|
|
7
|
+
*
|
|
8
|
+
* Original request (2026-07-28): replace Dashboard Workflow Progress with ReadonlyKanban.
|
|
9
|
+
*/
|
|
2
10
|
const DASHBOARD_RECENT_LIST_LIMIT = 10;
|
|
11
|
+
const ARCHIVE_RANGE_DAYS = {
|
|
12
|
+
"7d": 7,
|
|
13
|
+
"30d": 30,
|
|
14
|
+
"90d": 90,
|
|
15
|
+
all: null
|
|
16
|
+
};
|
|
17
|
+
const ARCHIVE_DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})(?:-|$)/;
|
|
18
|
+
/** Parse a valid UTC calendar date from an archive id prefix. */
|
|
19
|
+
function parseDatedArchiveIdTimestamp(id) {
|
|
20
|
+
const match = ARCHIVE_DATE_PREFIX.exec(id);
|
|
21
|
+
if (!match) return null;
|
|
22
|
+
const year = Number(match[1]);
|
|
23
|
+
const month = Number(match[2]);
|
|
24
|
+
const day = Number(match[3]);
|
|
25
|
+
const timestamp = Date.UTC(year, month - 1, day);
|
|
26
|
+
const parsed = new Date(timestamp);
|
|
27
|
+
if (!Number.isFinite(timestamp) || parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) return null;
|
|
28
|
+
return timestamp;
|
|
29
|
+
}
|
|
30
|
+
/** Resolve the archive timestamp from its dated id, then its physical update time. */
|
|
31
|
+
function resolveArchiveTimestamp(archive) {
|
|
32
|
+
return parseDatedArchiveIdTimestamp(archive.id) ?? archive.updatedAt;
|
|
33
|
+
}
|
|
34
|
+
/** Test whether an archive belongs to a user-selected trailing range. */
|
|
35
|
+
function isArchiveInRange(archive, range, now = Date.now()) {
|
|
36
|
+
const days = ARCHIVE_RANGE_DAYS[range];
|
|
37
|
+
if (days === null) return true;
|
|
38
|
+
return resolveArchiveTimestamp(archive) >= now - days * 24 * 60 * 60 * 1e3;
|
|
39
|
+
}
|
|
3
40
|
function compareDashboardItemsByUpdatedAt(left, right) {
|
|
4
41
|
return right.updatedAt - left.updatedAt || left.id.localeCompare(right.id);
|
|
5
42
|
}
|
|
@@ -9,6 +46,10 @@ function sortDashboardItemsByUpdatedAt(items) {
|
|
|
9
46
|
function selectRecentDashboardItems(items, limit = DASHBOARD_RECENT_LIST_LIMIT) {
|
|
10
47
|
return sortDashboardItemsByUpdatedAt(items).slice(0, Math.max(0, Math.trunc(limit)));
|
|
11
48
|
}
|
|
49
|
+
/** Select recent archives by objective archive time rather than incidental directory mtime. */
|
|
50
|
+
function selectRecentDashboardArchives(items, limit = DASHBOARD_RECENT_LIST_LIMIT) {
|
|
51
|
+
return [...items].sort((left, right) => resolveArchiveTimestamp(right) - resolveArchiveTimestamp(left) || left.id.localeCompare(right.id)).slice(0, Math.max(0, Math.trunc(limit)));
|
|
52
|
+
}
|
|
12
53
|
|
|
13
54
|
//#endregion
|
|
14
|
-
export { DASHBOARD_RECENT_LIST_LIMIT, compareDashboardItemsByUpdatedAt, selectRecentDashboardItems, sortDashboardItemsByUpdatedAt };
|
|
55
|
+
export { DASHBOARD_RECENT_LIST_LIMIT, compareDashboardItemsByUpdatedAt, isArchiveInRange, parseDatedArchiveIdTimestamp, resolveArchiveTimestamp, selectRecentDashboardArchives, selectRecentDashboardItems, sortDashboardItemsByUpdatedAt };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { d as TrackedTaskProgressSchema } from "./schemas-BFroDdOC.mjs";
|
|
2
|
+
import { s as CliProjectionStateNameSchema, u as createCliProjectionStateSchema } from "./cli-projection-vO3-FJg5.mjs";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
//#region src/dashboard-types.ts
|
|
6
|
+
/**
|
|
7
|
+
* Orthogonal intents (updated 2026-07-23 Asia/Shanghai):
|
|
8
|
+
* 1. Define Dashboard metrics, trends, planning projections, and Git snapshot contracts.
|
|
9
|
+
* 2. Preserve backend-issued Code binding provenance on live Git snapshots.
|
|
10
|
+
* 3. Split independently refreshable Summary and Trends facts from the aggregate Dashboard compatibility view.
|
|
11
|
+
* 4. Carry objective Kanban phase counts and bounded archive summaries without workflow inference.
|
|
12
|
+
*
|
|
13
|
+
* Original request (2026-07-19): "代码已经提交,开始review。如果有问题,那么可更新change。"
|
|
14
|
+
* Derived requirement (2026-07-19): Checkpoint 6.11 binds Dashboard snapshots to their Code token.
|
|
15
|
+
* Original request (2026-07-23): "现在页面数据的加载数据非常慢(比如dashboard页面、changes页面都要等待非常久,页面刷新后,似乎后台没有缓存一样,也要加载很久。"
|
|
16
|
+
* Original request (2026-07-28): replace Dashboard Workflow Progress with ReadonlyKanban.
|
|
17
|
+
*/
|
|
18
|
+
const DASHBOARD_METRIC_KEYS = [
|
|
19
|
+
"specifications",
|
|
20
|
+
"requirements",
|
|
21
|
+
"activeChanges",
|
|
22
|
+
"inProgressChanges",
|
|
23
|
+
"completedChanges",
|
|
24
|
+
"taskCompletionPercent"
|
|
25
|
+
];
|
|
26
|
+
const DashboardTrendPointSchema = z.object({
|
|
27
|
+
ts: z.number(),
|
|
28
|
+
value: z.number()
|
|
29
|
+
});
|
|
30
|
+
const DashboardTriColorTrendPointSchema = z.object({
|
|
31
|
+
ts: z.number(),
|
|
32
|
+
add: z.number(),
|
|
33
|
+
modify: z.number(),
|
|
34
|
+
delete: z.number()
|
|
35
|
+
});
|
|
36
|
+
const DashboardTrendRecordSchema = z.object({
|
|
37
|
+
specifications: z.array(DashboardTrendPointSchema),
|
|
38
|
+
requirements: z.array(DashboardTrendPointSchema),
|
|
39
|
+
activeChanges: z.array(DashboardTrendPointSchema),
|
|
40
|
+
inProgressChanges: z.array(DashboardTrendPointSchema),
|
|
41
|
+
completedChanges: z.array(DashboardTrendPointSchema),
|
|
42
|
+
taskCompletionPercent: z.array(DashboardTrendPointSchema)
|
|
43
|
+
});
|
|
44
|
+
const DashboardTriColorTrendRecordSchema = z.object({
|
|
45
|
+
specifications: z.array(DashboardTriColorTrendPointSchema),
|
|
46
|
+
requirements: z.array(DashboardTriColorTrendPointSchema),
|
|
47
|
+
activeChanges: z.array(DashboardTriColorTrendPointSchema),
|
|
48
|
+
inProgressChanges: z.array(DashboardTriColorTrendPointSchema),
|
|
49
|
+
completedChanges: z.array(DashboardTriColorTrendPointSchema),
|
|
50
|
+
taskCompletionPercent: z.array(DashboardTriColorTrendPointSchema)
|
|
51
|
+
});
|
|
52
|
+
const DashboardTrendKindsSchema = z.object({
|
|
53
|
+
specifications: z.enum(["monotonic", "bidirectional"]),
|
|
54
|
+
requirements: z.enum(["monotonic", "bidirectional"]),
|
|
55
|
+
activeChanges: z.enum(["monotonic", "bidirectional"]),
|
|
56
|
+
inProgressChanges: z.enum(["monotonic", "bidirectional"]),
|
|
57
|
+
completedChanges: z.enum(["monotonic", "bidirectional"]),
|
|
58
|
+
taskCompletionPercent: z.enum(["monotonic", "bidirectional"])
|
|
59
|
+
});
|
|
60
|
+
const DashboardCardAvailabilitySchema = z.discriminatedUnion("state", [z.object({ state: z.literal("ok") }), z.object({
|
|
61
|
+
state: z.literal("invalid"),
|
|
62
|
+
reason: z.enum(["semantic-uncomputable", "objective-history-unavailable"])
|
|
63
|
+
})]);
|
|
64
|
+
const DashboardCardAvailabilityRecordSchema = z.object({
|
|
65
|
+
specifications: DashboardCardAvailabilitySchema,
|
|
66
|
+
requirements: DashboardCardAvailabilitySchema,
|
|
67
|
+
activeChanges: DashboardCardAvailabilitySchema,
|
|
68
|
+
inProgressChanges: DashboardCardAvailabilitySchema,
|
|
69
|
+
completedChanges: DashboardCardAvailabilitySchema,
|
|
70
|
+
taskCompletionPercent: DashboardCardAvailabilitySchema
|
|
71
|
+
});
|
|
72
|
+
const DashboardSummarySchema = z.object({
|
|
73
|
+
specifications: z.number(),
|
|
74
|
+
requirements: z.number(),
|
|
75
|
+
activeChanges: z.number(),
|
|
76
|
+
inProgressChanges: z.number(),
|
|
77
|
+
completedChanges: z.number(),
|
|
78
|
+
archivedTasksCompleted: z.number(),
|
|
79
|
+
tasksTotal: z.number(),
|
|
80
|
+
tasksCompleted: z.number(),
|
|
81
|
+
taskCompletionPercent: z.number().nullable()
|
|
82
|
+
});
|
|
83
|
+
const DashboardGitDiffStatsSchema = z.object({
|
|
84
|
+
files: z.number(),
|
|
85
|
+
insertions: z.number(),
|
|
86
|
+
deletions: z.number()
|
|
87
|
+
});
|
|
88
|
+
const DashboardGitEntrySchema = z.discriminatedUnion("type", [z.object({
|
|
89
|
+
type: z.literal("commit"),
|
|
90
|
+
hash: z.string(),
|
|
91
|
+
title: z.string(),
|
|
92
|
+
committedAt: z.number(),
|
|
93
|
+
relatedChanges: z.array(z.string()),
|
|
94
|
+
diff: DashboardGitDiffStatsSchema
|
|
95
|
+
}), z.object({
|
|
96
|
+
type: z.literal("uncommitted"),
|
|
97
|
+
title: z.string(),
|
|
98
|
+
updatedAt: z.number().nullable(),
|
|
99
|
+
relatedChanges: z.array(z.string()),
|
|
100
|
+
diff: DashboardGitDiffStatsSchema
|
|
101
|
+
})]);
|
|
102
|
+
const DashboardGitWorktreeSchema = z.object({
|
|
103
|
+
path: z.string(),
|
|
104
|
+
relativePath: z.string(),
|
|
105
|
+
pathAvailable: z.boolean(),
|
|
106
|
+
branchName: z.string(),
|
|
107
|
+
detached: z.boolean(),
|
|
108
|
+
isCurrent: z.boolean(),
|
|
109
|
+
ahead: z.number(),
|
|
110
|
+
behind: z.number(),
|
|
111
|
+
diff: DashboardGitDiffStatsSchema,
|
|
112
|
+
entries: z.array(DashboardGitEntrySchema)
|
|
113
|
+
});
|
|
114
|
+
const DashboardGitSnapshotSchema = z.object({
|
|
115
|
+
bindingToken: z.string().nullable(),
|
|
116
|
+
defaultBranch: z.string(),
|
|
117
|
+
worktrees: z.array(DashboardGitWorktreeSchema)
|
|
118
|
+
});
|
|
119
|
+
const DashboardSummaryProjectionSchema = z.object({
|
|
120
|
+
summary: DashboardSummarySchema,
|
|
121
|
+
specifications: z.array(z.object({
|
|
122
|
+
id: z.string(),
|
|
123
|
+
name: z.string(),
|
|
124
|
+
requirements: z.number(),
|
|
125
|
+
updatedAt: z.number()
|
|
126
|
+
})),
|
|
127
|
+
activeChanges: z.array(z.object({
|
|
128
|
+
id: z.string(),
|
|
129
|
+
name: z.string(),
|
|
130
|
+
trackedTaskProgress: TrackedTaskProgressSchema,
|
|
131
|
+
updatedAt: z.number()
|
|
132
|
+
})),
|
|
133
|
+
trackedTaskPhaseCounts: z.object({
|
|
134
|
+
"no-tasks": z.number(),
|
|
135
|
+
"in-progress": z.number(),
|
|
136
|
+
complete: z.number()
|
|
137
|
+
}),
|
|
138
|
+
recentArchives: z.array(z.object({
|
|
139
|
+
id: z.string(),
|
|
140
|
+
name: z.string(),
|
|
141
|
+
trackedTaskProgress: TrackedTaskProgressSchema,
|
|
142
|
+
archivedAt: z.number(),
|
|
143
|
+
updatedAt: z.number()
|
|
144
|
+
}))
|
|
145
|
+
});
|
|
146
|
+
const DashboardTrendsProjectionSchema = z.object({
|
|
147
|
+
trends: DashboardTrendRecordSchema,
|
|
148
|
+
triColorTrends: DashboardTriColorTrendRecordSchema,
|
|
149
|
+
trendKinds: DashboardTrendKindsSchema,
|
|
150
|
+
cardAvailability: DashboardCardAvailabilityRecordSchema,
|
|
151
|
+
trendMeta: z.object({
|
|
152
|
+
pointLimit: z.number(),
|
|
153
|
+
lastUpdatedAt: z.number()
|
|
154
|
+
})
|
|
155
|
+
});
|
|
156
|
+
const DashboardOverviewSchema = DashboardSummaryProjectionSchema.merge(DashboardTrendsProjectionSchema).extend({ git: DashboardGitSnapshotSchema });
|
|
157
|
+
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/dashboard-summary-transport.ts
|
|
160
|
+
/**
|
|
161
|
+
* Orthogonal intents (updated 2026-07-27 Asia/Shanghai):
|
|
162
|
+
* 1. Define browser-safe opaque identity and wake-up contracts for Dashboard Summary v2.
|
|
163
|
+
* 2. Define the full typed Summary projection state without exposing Planning-root filesystem provenance.
|
|
164
|
+
* 3. Preserve retained versus current authority across fresh browser Documents.
|
|
165
|
+
*
|
|
166
|
+
* Original request (2026-07-23): "在已有content的时候,服务端推送变更,然后客户端收到推送通知,于是开始加载更新数据。"
|
|
167
|
+
* Original request (2026-07-27): "Dashboard页面每次页面刷新的时候,它仍然要加载很多?"
|
|
168
|
+
*/
|
|
169
|
+
/** Opaque Server-issued identity; it is derived from, but never contains, a Planning-root path. */
|
|
170
|
+
const DashboardSummaryIdentitySchema = z.string().regex(/^dashboard-summary-v2:[A-Za-z0-9_-]{43}$/);
|
|
171
|
+
/** Reasons that can wake the migrated Summary adapter in this bounded v2 slice. */
|
|
172
|
+
const DashboardSummaryInvalidationCauseSchema = z.enum([
|
|
173
|
+
"initial",
|
|
174
|
+
"server-push",
|
|
175
|
+
"root-rebind"
|
|
176
|
+
]);
|
|
177
|
+
/** Data-free subscription event. Replacement Summary data always arrives through the typed pull. */
|
|
178
|
+
const DashboardSummaryInvalidationSchema = z.object({
|
|
179
|
+
identity: DashboardSummaryIdentitySchema,
|
|
180
|
+
workGeneration: z.number().int().nonnegative(),
|
|
181
|
+
snapshotGeneration: z.number().int().nonnegative().nullable(),
|
|
182
|
+
state: CliProjectionStateNameSchema,
|
|
183
|
+
cause: DashboardSummaryInvalidationCauseSchema
|
|
184
|
+
}).strict();
|
|
185
|
+
/** Full Summary Pull state correlated to the exact Server-owned work identity and generation. */
|
|
186
|
+
const DashboardSummaryProjectionStateSchema = createCliProjectionStateSchema(DashboardSummaryProjectionSchema);
|
|
187
|
+
|
|
188
|
+
//#endregion
|
|
189
|
+
export { DASHBOARD_METRIC_KEYS as a, DashboardSummaryProjectionSchema as c, DashboardSummaryProjectionStateSchema as i, DashboardTrendsProjectionSchema as l, DashboardSummaryInvalidationCauseSchema as n, DashboardGitSnapshotSchema as o, DashboardSummaryInvalidationSchema as r, DashboardOverviewSchema as s, DashboardSummaryIdentitySchema as t };
|