dsh-hams 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +11335 -0
  3. package/package.json +9 -5
  4. package/src/domain/check.ts +0 -193
  5. package/src/domain/errors.ts +0 -59
  6. package/src/domain/evidence.ts +0 -134
  7. package/src/domain/ids.ts +0 -31
  8. package/src/host/chat-runtime.ts +0 -489
  9. package/src/host/dsh-adapter.ts +0 -867
  10. package/src/host/session-adapter.ts +0 -276
  11. package/src/http/handler.ts +0 -1132
  12. package/src/index.js +0 -53
  13. package/src/service/audit.ts +0 -92
  14. package/src/service/chat.ts +0 -1100
  15. package/src/service/contracts.ts +0 -193
  16. package/src/service/defaults.ts +0 -182
  17. package/src/service/deliverables.ts +0 -240
  18. package/src/service/hams.ts +0 -3103
  19. package/src/service/knowledge.ts +0 -940
  20. package/src/service/member-config.ts +0 -39
  21. package/src/service/members.ts +0 -506
  22. package/src/service/memory.ts +0 -375
  23. package/src/service/permissions.ts +0 -118
  24. package/src/service/project-lifecycle.ts +0 -233
  25. package/src/service/projects.ts +0 -840
  26. package/src/service/receipts.ts +0 -63
  27. package/src/service/templates.ts +0 -140
  28. package/src/service/tick.ts +0 -751
  29. package/src/service/tools.ts +0 -711
  30. package/src/service/types.ts +0 -219
  31. package/src/service/work-item-create.ts +0 -159
  32. package/src/service/workspace-profile.ts +0 -443
  33. package/src/store/backup.ts +0 -239
  34. package/src/store/bootstrap.ts +0 -225
  35. package/src/store/db.ts +0 -179
  36. package/src/store/lock.ts +0 -194
  37. package/src/store/migrations.ts +0 -211
  38. package/src/store/schema/001_p1.sql +0 -846
  39. package/src/store/schema/001_p1.sql.ts +0 -865
  40. package/src/store/schema/002_knowledge.sql +0 -54
  41. package/src/store/schema/002_knowledge.sql.ts +0 -68
  42. package/src/store/schema/003_projects.sql.ts +0 -3
  43. package/src/store/schema/004_team.sql.ts +0 -50
  44. package/src/store/schema/005_target_check.sql.ts +0 -22
  45. package/src/store/schema/006_target_flow.sql.ts +0 -19
  46. package/src/store/schema/007_project_delete.sql.ts +0 -17
  47. package/src/store/schema/008_memory.sql.ts +0 -47
  48. package/src/store/schema/generate-projects.mjs +0 -16
  49. package/src/store/seed.ts +0 -114
@@ -1,63 +0,0 @@
1
- /**
2
- * 写命令幂等:`command_receipt`。
3
- *
4
- * 与 `outbox` 分开(backend-design §4.9):这里回答「这个请求做过没有」,
5
- * outbox 回答「这个外部动作发出去了没有」。同键同载荷返回首次回执;同键不同载荷
6
- * 直接拒绝(IDEMPOTENCY_MISMATCH),绝不「按新载荷再跑一次」。
7
- */
8
- import type { DatabaseSync } from 'node:sqlite'
9
- import { createHash } from 'node:crypto'
10
-
11
- export function stableStringify(value: unknown): string {
12
- if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null'
13
- if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(',')}]`
14
- const record = value as Record<string, unknown>
15
- const keys = Object.keys(record).sort()
16
- return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(',')}}`
17
- }
18
-
19
- export function hashPayload(value: unknown): string {
20
- return createHash('sha256').update(stableStringify(value)).digest('hex')
21
- }
22
-
23
- export function receiptScopeKey(principalId: string, action: string, idempotencyKey: string): string {
24
- return createHash('sha256').update(`${principalId}\u0000${action}\u0000${idempotencyKey}`).digest('hex')
25
- }
26
-
27
- export interface StoredReceipt {
28
- payloadHash: string
29
- receiptJson: string
30
- }
31
-
32
- export function loadReceipt(db: DatabaseSync, scopeKey: string): StoredReceipt | undefined {
33
- const row = db
34
- .prepare('SELECT payload_hash, receipt_json FROM command_receipt WHERE scope_key = ?')
35
- .get(scopeKey) as { payload_hash: string; receipt_json: string } | undefined
36
- return row ? { payloadHash: row.payload_hash, receiptJson: row.receipt_json } : undefined
37
- }
38
-
39
- export interface SaveReceiptInput {
40
- scopeKey: string
41
- commandId: string
42
- principalId: string
43
- action: string
44
- payloadHash: string
45
- receiptJson: string
46
- at: number
47
- }
48
-
49
- export function saveReceipt(db: DatabaseSync, input: SaveReceiptInput): void {
50
- db.prepare(
51
- `INSERT INTO command_receipt
52
- (scope_key, command_id, principal_id, action, payload_hash, receipt_json, created_at)
53
- VALUES (?, ?, ?, ?, ?, ?, ?)`,
54
- ).run(
55
- input.scopeKey,
56
- input.commandId,
57
- input.principalId,
58
- input.action,
59
- input.payloadHash,
60
- input.receiptJson,
61
- input.at,
62
- )
63
- }
@@ -1,140 +0,0 @@
1
- /**
2
- * 起步模板与旧样例清理。
3
- *
4
- * 2026-11-15 起,空库不再造「电池告警追踪」这个示例模板,改为一条与真实使用
5
- * 方式一致的通用模板:**研究与交付推进**——交付物一份(doc)+ 过程记录一份(log),
6
- * 三天后复查,owner 审批 72 小时、不自动关单。理由有两条:
7
- *
8
- * 1. 电池资产运营是设计期的首个场景,不是当前工作;把示例写进用户库会让人以为
9
- * 系统里已经有业务数据。
10
- * 2. 通用模板能覆盖研究、开发、数据运维三类工作项,建单后都能走到「申请关单」,
11
- * 不会出现「模板是别人业务的、自己的单关不掉」。
12
- *
13
- * 旧库升级时由工作区画像的 `cleanupTemplates` 调用 `removeTemplateIfUnused`:
14
- * 只有模板确实存在、且没有任何工作项引用它的版本时才删除,历史单据不受影响。
15
- */
16
- import type { DatabaseSync } from 'node:sqlite'
17
-
18
- export const STARTER_TEMPLATE = {
19
- id: 'tpl-research-delivery',
20
- versionId: 'tpl-research-delivery-v1',
21
- key: 'research_delivery',
22
- name: '研究与交付推进',
23
- domain: '研究',
24
- category: '研究推进',
25
- /** 交付物一份 + 过程记录一份;720 小时是上限,不是要求每天都补。 */
26
- requiredEvidence: [
27
- { kind: 'doc', min_count: 1, max_age_hours: 720 },
28
- { kind: 'log', min_count: 1, max_age_hours: 720 },
29
- ],
30
- checkPolicy: { mode: 'after_hours', hours: 72 },
31
- reviewPolicy: { approver: 'owner', expires_hours: 72, auto_close: false },
32
- } as const
33
-
34
- /**
35
- * 空库首次启动建一次起步模板,并记在 hams_meta。只补默认、不覆盖:
36
- * 只要库里已有模板(或元数据已记),就不再造。
37
- */
38
- export function ensureStarterTemplate(db: DatabaseSync, publishedBy: string, now = Date.now()): string | null {
39
- const seeded = db.prepare("SELECT value FROM hams_meta WHERE key = 'starter_template_at'").get() as
40
- | { value: string }
41
- | undefined
42
- if (seeded) return null
43
- const existing = db.prepare('SELECT id FROM work_template LIMIT 1').get() as { id: string } | undefined
44
-
45
- db.exec('BEGIN IMMEDIATE')
46
- try {
47
- if (!existing) {
48
- upsertTemplate(db, publishedBy, now, STARTER_TEMPLATE)
49
- }
50
- db.prepare("INSERT OR REPLACE INTO hams_meta (key, value) VALUES ('starter_template_at', ?)").run(String(now))
51
- db.exec('COMMIT')
52
- return existing ? null : STARTER_TEMPLATE.versionId
53
- } catch (error) {
54
- if (db.isTransaction) db.exec('ROLLBACK')
55
- throw error
56
- }
57
- }
58
-
59
- export interface TemplateDefinition {
60
- id: string
61
- versionId: string
62
- key: string
63
- name: string
64
- domain: string
65
- category: string
66
- requiredEvidence: readonly { kind: string; min_count: number; max_age_hours?: number }[]
67
- checkPolicy: Record<string, unknown>
68
- reviewPolicy: Record<string, unknown>
69
- }
70
-
71
- /** 幂等:按 key 找模板与版本;已存在就直接用已发布版本。 */
72
- export function upsertTemplate(
73
- db: DatabaseSync,
74
- publishedBy: string,
75
- now: number,
76
- definition: TemplateDefinition,
77
- ): string {
78
- const existing = db.prepare('SELECT * FROM work_template WHERE key = ?').get(definition.key) as
79
- | { id: string; published_version_id: string | null }
80
- | undefined
81
- if (existing?.published_version_id) return existing.published_version_id
82
-
83
- const templateId = existing?.id ?? definition.id
84
- if (!existing) {
85
- db.prepare('INSERT INTO work_template (id, key, name, domain, category) VALUES (?, ?, ?, ?, ?)').run(
86
- templateId,
87
- definition.key,
88
- definition.name,
89
- definition.domain,
90
- definition.category,
91
- )
92
- }
93
- const versionId = definition.versionId
94
- db.prepare(
95
- `INSERT INTO work_template_version
96
- (id, template_id, version, required_evidence_json, validator_key, validator_params_json,
97
- check_policy_json, review_policy_json, misfire_policy, status, published_by, published_at)
98
- VALUES (?, ?, 1, ?, NULL, '{}', ?, ?, 'each', 'published', ?, ?)`,
99
- ).run(
100
- versionId,
101
- templateId,
102
- JSON.stringify(definition.requiredEvidence),
103
- JSON.stringify(definition.checkPolicy),
104
- JSON.stringify(definition.reviewPolicy),
105
- publishedBy,
106
- now,
107
- )
108
- db.prepare('UPDATE work_template SET published_version_id = ? WHERE id = ?').run(versionId, templateId)
109
- return versionId
110
- }
111
-
112
- /**
113
- * 删除一个旧示例模板:只在**没有任何工作项引用它的版本**时执行。
114
- * 返回 true 表示确实删了。
115
- */
116
- export function removeTemplateIfUnused(db: DatabaseSync, templateIdOrKey: string): boolean {
117
- const template = db
118
- .prepare('SELECT id, published_version_id FROM work_template WHERE id = ? OR key = ?')
119
- .get(templateIdOrKey, templateIdOrKey) as { id: string; published_version_id: string | null } | undefined
120
- if (!template) return false
121
- const versions = db.prepare('SELECT id FROM work_template_version WHERE template_id = ?').all(template.id) as {
122
- id: string
123
- }[]
124
- if (!versions.length) {
125
- db.prepare('DELETE FROM work_template WHERE id = ?').run(template.id)
126
- return true
127
- }
128
- const placeholders = versions.map(() => '?').join(',')
129
- const versionIds = versions.map((version) => version.id) as never[]
130
- for (const table of ['work_item', 'work_item_check', 'schedule']) {
131
- const referenced = db
132
- .prepare(`SELECT 1 AS ok FROM ${table} WHERE template_version_id IN (${placeholders}) LIMIT 1`)
133
- .get(...versionIds) as { ok: number } | undefined
134
- if (referenced) return false
135
- }
136
- db.prepare('UPDATE work_template SET published_version_id = NULL WHERE id = ?').run(template.id)
137
- db.prepare('DELETE FROM work_template_version WHERE template_id = ?').run(template.id)
138
- db.prepare('DELETE FROM work_template WHERE id = ?').run(template.id)
139
- return true
140
- }