create-principles-disciple 1.118.0 → 1.119.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/console/dist/server/index.js +17 -1
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +77 -0
- package/console/dist/server/models/ActivationsConsoleModel.js +322 -4
- package/console/dist/server/models/ReceiptsConsoleModel.d.ts +42 -0
- package/console/dist/server/models/ReceiptsConsoleModel.js +160 -0
- package/console/dist/server/routes/activations.d.ts +6 -1
- package/console/dist/server/routes/activations.js +142 -1
- package/console/dist/server/routes/receipts.d.ts +8 -0
- package/console/dist/server/routes/receipts.js +63 -0
- package/console/dist/ui/App.js +6 -3
- package/console/dist/ui/api.d.ts +40 -3
- package/console/dist/ui/api.js +94 -3
- package/console/dist/ui/i18n/en.json +75 -0
- package/console/dist/ui/i18n/zh-CN.json +75 -0
- package/console/dist/ui/pages/activation/ActivationPage.js +114 -5
- package/console/dist/ui/pages/activation/ActivationValidators.js +3 -0
- package/console/dist/ui/pages/focus/FocusPage.js +16 -3
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +17 -3
- package/console/dist/ui/utils/validators.d.ts +100 -0
- package/console/dist/ui/utils/validators.js +133 -0
- package/console/dist/web/assets/app.css +34 -0
- package/console/dist/web/assets/app.js +704 -14
- package/console/package.json +2 -0
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +8 -2
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.js +91 -0
- package/core/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js +83 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.js +48 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js +141 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.js +31 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js +311 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/activation-control-types.d.ts +61 -0
- package/core/dist/runtime-v2/activation/activation-control-types.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/activation-control-types.js +2 -0
- package/core/dist/runtime-v2/activation/activation-control-types.js.map +1 -0
- package/core/dist/runtime-v2/activation/index.d.ts +14 -0
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +7 -0
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/openclaw-promotion-checks.d.ts +30 -0
- package/core/dist/runtime-v2/activation/openclaw-promotion-checks.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/openclaw-promotion-checks.js +124 -0
- package/core/dist/runtime-v2/activation/openclaw-promotion-checks.js.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts +17 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js +55 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts +21 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.js +44 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.js.map +1 -0
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts +104 -0
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js +86 -0
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js.map +1 -0
- package/core/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.d.ts +25 -0
- package/core/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.js +23 -0
- package/core/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.js.map +1 -0
- package/core/dist/runtime-v2/activation/rulecode-shadow-summary.d.ts +14 -0
- package/core/dist/runtime-v2/activation/rulecode-shadow-summary.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/rulecode-shadow-summary.js +57 -0
- package/core/dist/runtime-v2/activation/rulecode-shadow-summary.js.map +1 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-safety-store.d.ts +40 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-safety-store.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-safety-store.js +461 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-safety-store.js.map +1 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js +24 -6
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js +19 -4
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js +10 -0
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +13 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +15 -2
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +2 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +2 -2
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +1 -1
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/legacy-rule-contract-scanner.test.js +20 -1
- package/core/dist/runtime-v2/internalization/__tests__/legacy-rule-contract-scanner.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/legacy-rule-contract-scanner.d.ts +4 -4
- package/core/dist/runtime-v2/internalization/legacy-rule-contract-scanner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/legacy-rule-contract-scanner.js +92 -5
- package/core/dist/runtime-v2/internalization/legacy-rule-contract-scanner.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js +11 -11
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +111 -0
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/host-runtime/dist/host-liveness-contract.d.ts +3 -0
- package/host-runtime/dist/host-liveness-contract.js +18 -0
- package/host-runtime/dist/index.d.ts +1 -0
- package/host-runtime/dist/index.js +1 -0
- package/host-runtime/dist/legacy-rule-contract-symbols.js +88 -1
- package/host-runtime/dist/production-rulehost-gate.js +33 -16
- package/package.json +2 -2
- package/pd-cli/dist/commands/__tests__/runtime-activation-nextaction.test.js +3 -3
- package/pd-cli/dist/commands/__tests__/runtime-activation-nextaction.test.js.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts +15 -3
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +160 -49
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/plugin/dist/bundle.js +730 -565
- package/plugin/dist/core/rule-host.d.ts +0 -19
- package/plugin/dist/core/rulecode-safety-circuit.d.ts +13 -0
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Receipts Console Model — PRI-533 (SPEC §5.4).
|
|
3
|
+
*
|
|
4
|
+
* Read-side model for the principle receipt ledger (principle_applications,
|
|
5
|
+
* written by the plugin when principle_receipt_ledger is enabled). Serves:
|
|
6
|
+
* - per-principle receipt history (effect/presence counts + bounded timeline)
|
|
7
|
+
* - per-principle counts for the activations page columns
|
|
8
|
+
*
|
|
9
|
+
* Degradation rules (rc-9): state.db missing, table missing (pre-PRI-531
|
|
10
|
+
* workspace), or the ledger flag disabled → status degraded with reason +
|
|
11
|
+
* nextAction. Never throws to the route.
|
|
12
|
+
*
|
|
13
|
+
* rc-1: SQL rows are typed unknown and narrowed with typeof per column.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { SqliteConnection } from '@principles/core/runtime-v2';
|
|
18
|
+
import { computeFlagsFromLoadResult, loadPdConfig } from '../config/pd-config-store.js';
|
|
19
|
+
const KINDS = new Set(['rule_blocked', 'auto_correct_applied', 'self_reported', 'prompt_injected']);
|
|
20
|
+
const LEVELS = new Set(['effect', 'presence']);
|
|
21
|
+
const TIMELINE_LIMIT = 50;
|
|
22
|
+
function asNullableString(value) {
|
|
23
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
24
|
+
}
|
|
25
|
+
function toEvent(row) {
|
|
26
|
+
if (typeof row.kind !== 'string' || !KINDS.has(row.kind))
|
|
27
|
+
return null;
|
|
28
|
+
if (typeof row.level !== 'string' || !LEVELS.has(row.level))
|
|
29
|
+
return null;
|
|
30
|
+
if (typeof row.created_at !== 'string')
|
|
31
|
+
return null;
|
|
32
|
+
return {
|
|
33
|
+
kind: row.kind,
|
|
34
|
+
level: row.level,
|
|
35
|
+
sessionId: asNullableString(row.session_id),
|
|
36
|
+
toolName: asNullableString(row.tool_name),
|
|
37
|
+
filePath: asNullableString(row.file_path),
|
|
38
|
+
digest: asNullableString(row.digest),
|
|
39
|
+
createdAt: row.created_at,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function isMissingTableError(err) {
|
|
43
|
+
return err instanceof Error && err.message.includes('no such table');
|
|
44
|
+
}
|
|
45
|
+
export class ReceiptsConsoleModel {
|
|
46
|
+
workspaceDir;
|
|
47
|
+
constructor(workspaceDir) {
|
|
48
|
+
this.workspaceDir = workspaceDir;
|
|
49
|
+
}
|
|
50
|
+
async getPrincipleReceipts(principleId) {
|
|
51
|
+
const guard = this.precheck();
|
|
52
|
+
if (guard) {
|
|
53
|
+
return { ...guard, principleId, effectCount: 0, presenceCount: 0, lastEffectAt: null, events: [] };
|
|
54
|
+
}
|
|
55
|
+
const conn = new SqliteConnection({ workspaceDir: this.workspaceDir, readonly: true, bootstrapIfMissing: false });
|
|
56
|
+
try {
|
|
57
|
+
const rows = conn.getDb().prepare('SELECT kind, level, session_id, tool_name, file_path, digest, created_at FROM principle_applications WHERE principle_id = ? ORDER BY created_at DESC, id DESC LIMIT ?').all(principleId, TIMELINE_LIMIT);
|
|
58
|
+
const events = [];
|
|
59
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
60
|
+
const event = toEvent(row);
|
|
61
|
+
if (event)
|
|
62
|
+
events.push(event);
|
|
63
|
+
}
|
|
64
|
+
const counts = conn.getDb().prepare("SELECT level, COUNT(*) AS n, MAX(created_at) AS last_at FROM principle_applications WHERE principle_id = ? GROUP BY level").all(principleId);
|
|
65
|
+
let effectCount = 0;
|
|
66
|
+
let presenceCount = 0;
|
|
67
|
+
let lastEffectAt = null;
|
|
68
|
+
for (const row of Array.isArray(counts) ? counts : []) {
|
|
69
|
+
const rec = row;
|
|
70
|
+
if (rec.level === 'effect') {
|
|
71
|
+
effectCount = typeof rec.n === 'number' ? rec.n : 0;
|
|
72
|
+
lastEffectAt = asNullableString(rec.last_at);
|
|
73
|
+
}
|
|
74
|
+
else if (rec.level === 'presence') {
|
|
75
|
+
presenceCount = typeof rec.n === 'number' ? rec.n : 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { status: 'ok', principleId, effectCount, presenceCount, lastEffectAt, events };
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
if (isMissingTableError(err)) {
|
|
82
|
+
return {
|
|
83
|
+
status: 'degraded',
|
|
84
|
+
reason: 'principle_applications table not found — ledger not initialized on this workspace',
|
|
85
|
+
nextAction: 'Update the plugin to a version including PRI-531 and enable principle_receipt_ledger',
|
|
86
|
+
principleId, effectCount: 0, presenceCount: 0, lastEffectAt: null, events: [],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
conn.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async getReceiptCounts() {
|
|
96
|
+
const guard = this.precheck();
|
|
97
|
+
if (guard) {
|
|
98
|
+
return { status: guard.status, reason: guard.reason, nextAction: guard.nextAction, counts: [] };
|
|
99
|
+
}
|
|
100
|
+
const conn = new SqliteConnection({ workspaceDir: this.workspaceDir, readonly: true, bootstrapIfMissing: false });
|
|
101
|
+
try {
|
|
102
|
+
const rows = conn.getDb().prepare(`SELECT principle_id,
|
|
103
|
+
SUM(CASE WHEN level = 'effect' THEN 1 ELSE 0 END) AS effect_count,
|
|
104
|
+
SUM(CASE WHEN level = 'presence' THEN 1 ELSE 0 END) AS presence_count,
|
|
105
|
+
MAX(CASE WHEN level = 'effect' THEN created_at END) AS last_effect_at
|
|
106
|
+
FROM principle_applications GROUP BY principle_id`).all();
|
|
107
|
+
const counts = [];
|
|
108
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
109
|
+
const rec = row;
|
|
110
|
+
const principleId = asNullableString(rec.principle_id);
|
|
111
|
+
if (!principleId)
|
|
112
|
+
continue;
|
|
113
|
+
counts.push({
|
|
114
|
+
principleId,
|
|
115
|
+
effectCount: typeof rec.effect_count === 'number' ? rec.effect_count : 0,
|
|
116
|
+
presenceCount: typeof rec.presence_count === 'number' ? rec.presence_count : 0,
|
|
117
|
+
lastEffectAt: asNullableString(rec.last_effect_at),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return { status: 'ok', counts };
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
if (isMissingTableError(err)) {
|
|
124
|
+
return {
|
|
125
|
+
status: 'degraded',
|
|
126
|
+
reason: 'principle_applications table not found — ledger not initialized on this workspace',
|
|
127
|
+
nextAction: 'Update the plugin to a version including PRI-531 and enable principle_receipt_ledger',
|
|
128
|
+
counts: [],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
conn.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Shared preconditions: state.db exists + ledger flag enabled. Returns a
|
|
139
|
+
* degraded partial response when a precondition fails (rc-9), else null.
|
|
140
|
+
*/
|
|
141
|
+
precheck() {
|
|
142
|
+
const stateDbPath = path.join(this.workspaceDir, '.pd', 'state.db');
|
|
143
|
+
if (!fs.existsSync(stateDbPath)) {
|
|
144
|
+
return {
|
|
145
|
+
status: 'degraded',
|
|
146
|
+
reason: 'state.db not found — workspace may not be initialized',
|
|
147
|
+
nextAction: 'Run pd runtime diagnostics to check workspace state',
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const flags = computeFlagsFromLoadResult(loadPdConfig(this.workspaceDir));
|
|
151
|
+
if (flags.flags.principle_receipt_ledger?.enabled !== true) {
|
|
152
|
+
return {
|
|
153
|
+
status: 'degraded',
|
|
154
|
+
reason: 'principle_receipt_ledger flag is disabled — no receipt history is being recorded',
|
|
155
|
+
nextAction: 'Enable the flag in .pd/config.yaml: features.principle_receipt_ledger.enabled = true',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
|
|
2
|
+
import type { OwnerPromotionActor } from '@principles/core/runtime-v2';
|
|
3
|
+
export interface ActivationsRouteAuthority {
|
|
4
|
+
ownerActor: OwnerPromotionActor | null;
|
|
5
|
+
breakGlassActor: OwnerPromotionActor;
|
|
6
|
+
}
|
|
7
|
+
export declare function handleActivationsRoute(req: IncomingMessage, res: ServerResponse, workspaceDir: string, subPath: string, authority?: ActivationsRouteAuthority): Promise<void>;
|
|
3
8
|
export declare function disposeActivationsModels(): void;
|
|
@@ -29,9 +29,58 @@ function validateDisableRequest(body) {
|
|
|
29
29
|
}
|
|
30
30
|
return { ok: true, confirmed: true };
|
|
31
31
|
}
|
|
32
|
+
function mutationBody(body) {
|
|
33
|
+
if (!isRecord(body))
|
|
34
|
+
throw new Error('Request body must be a JSON object');
|
|
35
|
+
for (const field of ['idempotencyKey', 'reasonCode']) {
|
|
36
|
+
if (!Object.hasOwn(body, field) || typeof body[field] !== 'string' || body[field].trim().length === 0)
|
|
37
|
+
throw new Error(`Missing or invalid required field: ${field}`);
|
|
38
|
+
}
|
|
39
|
+
const { idempotencyKey, reasonCode } = body;
|
|
40
|
+
if (typeof idempotencyKey !== 'string' || typeof reasonCode !== 'string')
|
|
41
|
+
throw new Error('Required mutation fields are invalid');
|
|
42
|
+
const result = { idempotencyKey, reasonCode };
|
|
43
|
+
if (Object.hasOwn(body, 'note')) {
|
|
44
|
+
if (typeof body.note !== 'string')
|
|
45
|
+
throw new Error('Field "note" must be a string');
|
|
46
|
+
result.note = body.note;
|
|
47
|
+
}
|
|
48
|
+
if (Object.hasOwn(body, 'confirmed')) {
|
|
49
|
+
if (typeof body.confirmed !== 'boolean')
|
|
50
|
+
throw new Error('Field "confirmed" must be boolean');
|
|
51
|
+
result.confirmed = body.confirmed;
|
|
52
|
+
}
|
|
53
|
+
for (const field of ['artifactId', 'artifactDigest']) {
|
|
54
|
+
if (Object.hasOwn(body, field)) {
|
|
55
|
+
if (typeof body[field] !== 'string')
|
|
56
|
+
throw new Error(`Field "${field}" must be a string`);
|
|
57
|
+
result[field] = body[field];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const field of ['controlVersion', 'expectedVersion']) {
|
|
61
|
+
if (Object.hasOwn(body, field)) {
|
|
62
|
+
if (typeof body[field] !== 'number' || !Number.isInteger(body[field]))
|
|
63
|
+
throw new Error(`Field "${field}" must be an integer`);
|
|
64
|
+
result[field] = body[field];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
async function readJson(req) {
|
|
70
|
+
const chunks = [];
|
|
71
|
+
let totalSize = 0;
|
|
72
|
+
for await (const chunk of req) {
|
|
73
|
+
const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
74
|
+
totalSize += buf.length;
|
|
75
|
+
if (totalSize > MAX_BODY_SIZE)
|
|
76
|
+
throw new Error('payload_too_large');
|
|
77
|
+
chunks.push(buf);
|
|
78
|
+
}
|
|
79
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
80
|
+
}
|
|
32
81
|
// ── Route handler ────────────────────────────────────────────────────────────
|
|
33
82
|
/* eslint-disable @typescript-eslint/max-params */
|
|
34
|
-
export async function handleActivationsRoute(req, res, workspaceDir, subPath) {
|
|
83
|
+
export async function handleActivationsRoute(req, res, workspaceDir, subPath, authority) {
|
|
35
84
|
// GET /api/v1/activations
|
|
36
85
|
if (req.method === 'GET' && (subPath === '' || subPath === '/')) {
|
|
37
86
|
const model = getModel(workspaceDir);
|
|
@@ -45,6 +94,98 @@ export async function handleActivationsRoute(req, res, workspaceDir, subPath) {
|
|
|
45
94
|
}
|
|
46
95
|
return;
|
|
47
96
|
}
|
|
97
|
+
const mutationMatch = /^\/([^/]+)\/(continue-observing|promote|reject-after-shadow|emergency-deactivate|recover-to-shadow)$/.exec(subPath);
|
|
98
|
+
const pauseMatch = subPath === '/emergency-pause';
|
|
99
|
+
const releaseMatch = /^\/emergency-pause\/([^/]+)\/release$/.exec(subPath);
|
|
100
|
+
if (req.method === 'POST' && (mutationMatch || pauseMatch || releaseMatch)) {
|
|
101
|
+
let body;
|
|
102
|
+
try {
|
|
103
|
+
body = mutationBody(await readJson(req));
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
107
|
+
sendError(res, message === 'payload_too_large' ? 413 : 400, 'validation_error', message, { nextAction: 'Refresh the review and submit a valid bounded request.' });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const [, , matchedOperation] = mutationMatch ?? [];
|
|
111
|
+
const operation = matchedOperation ?? (pauseMatch ? 'emergency-pause' : 'release');
|
|
112
|
+
const governance = operation === 'continue-observing' || operation === 'promote' || operation === 'reject-after-shadow' || operation === 'recover-to-shadow' || operation === 'release';
|
|
113
|
+
const actor = governance ? authority?.ownerActor : (authority?.ownerActor ?? authority?.breakGlassActor);
|
|
114
|
+
if (!actor) {
|
|
115
|
+
sendError(res, 403, 'owner_authentication_required', 'This governance decision requires the configured Owner identity.', { nextAction: 'Configure PD_OWNER_ID and PD_OWNER_CREDENTIAL_ID, then authenticate with the Console token.' });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const input = { actor, idempotencyKey: body.idempotencyKey, reasonCode: body.reasonCode, ...(body.note === undefined ? {} : { note: body.note }) };
|
|
119
|
+
const model = getModel(workspaceDir);
|
|
120
|
+
try {
|
|
121
|
+
if (pauseMatch) {
|
|
122
|
+
sendSuccess(res, await model.pauseAllRuleCode(input));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (releaseMatch) {
|
|
126
|
+
const [, rawPauseId] = releaseMatch;
|
|
127
|
+
if (!rawPauseId || body.expectedVersion === undefined)
|
|
128
|
+
throw new Error('Pause ID and expectedVersion are required');
|
|
129
|
+
sendSuccess(res, await model.releaseRuleCodePause(decodeURIComponent(rawPauseId), body.expectedVersion, input));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const [, rawId] = mutationMatch ?? [];
|
|
133
|
+
if (!rawId)
|
|
134
|
+
throw new Error('Activation ID is required');
|
|
135
|
+
const activationId = decodeURIComponent(rawId);
|
|
136
|
+
if (operation === 'continue-observing')
|
|
137
|
+
sendSuccess(res, await model.continueObserving(activationId, input));
|
|
138
|
+
else if (operation === 'reject-after-shadow' || operation === 'emergency-deactivate')
|
|
139
|
+
sendSuccess(res, await model.deactivateRuleCode(activationId, operation === 'reject-after-shadow' ? 'reject_after_shadow' : 'emergency_deactivate', input));
|
|
140
|
+
else if (operation === 'recover-to-shadow') {
|
|
141
|
+
if (body.controlVersion === undefined)
|
|
142
|
+
throw new Error('Recovery requires controlVersion');
|
|
143
|
+
sendSuccess(res, await model.recoverRuleCodeToShadow(activationId, body.controlVersion, input));
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
if (!body.artifactId || !body.artifactDigest || body.controlVersion === undefined || body.confirmed !== true)
|
|
147
|
+
throw new Error('Promotion requires artifactId, artifactDigest, controlVersion, and confirmed=true');
|
|
148
|
+
const result = await model.promoteRuleCode(activationId, { artifactId: body.artifactId, artifactDigest: body.artifactDigest, controlVersion: body.controlVersion, confirmed: body.confirmed }, input);
|
|
149
|
+
if (!result.ok) {
|
|
150
|
+
sendError(res, 409, result.reasonCode, result.summary, { failedChecks: result.failedChecks, nextAction: result.nextAction });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
sendSuccess(res, result);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
158
|
+
sendError(res, message.includes('expected version') || message.includes('requires exactly one') ? 409 : 500, 'owner_decision_failed', message, { nextAction: 'Refresh the Owner review; no partial decision was applied.' });
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const ownerReviewMatch = /^\/([^/]+)\/owner-review$/.exec(subPath);
|
|
163
|
+
if (req.method === 'GET' && ownerReviewMatch) {
|
|
164
|
+
const [, rawId] = ownerReviewMatch;
|
|
165
|
+
if (!rawId) {
|
|
166
|
+
sendError(res, 400, 'invalid_id', 'Activation ID is missing');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
let activationId;
|
|
170
|
+
try {
|
|
171
|
+
activationId = decodeURIComponent(rawId);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
sendError(res, 400, 'invalid_id', 'Activation ID contains invalid URI encoding');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
sendSuccess(res, await getModel(workspaceDir).getOwnerReview(activationId, authority?.ownerActor !== null && authority?.ownerActor !== undefined));
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
182
|
+
if (message.includes('requires exactly one') || message.includes('not found'))
|
|
183
|
+
sendNotFound(res, message);
|
|
184
|
+
else
|
|
185
|
+
sendError(res, 500, 'owner_review_error', message, { nextAction: 'Keep the rule in shadow and inspect workspace integrity.' });
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
48
189
|
// POST /api/v1/activations/:id/disable
|
|
49
190
|
const disableExec = /^\/([^/]+)\/disable$/.exec(subPath);
|
|
50
191
|
if (req.method === 'POST' && disableExec) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Receipts API routes — PRI-533.
|
|
3
|
+
* GET /api/v1/receipts/counts → per-principle receipt counts
|
|
4
|
+
* GET /api/v1/receipts/principles/:principleId → per-principle receipt history
|
|
5
|
+
*/
|
|
6
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
7
|
+
export declare function handleReceiptsRoute(req: IncomingMessage, res: ServerResponse, workspaceDir: string, subPath: string): Promise<void>;
|
|
8
|
+
export declare function disposeReceiptsModels(): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ReceiptsConsoleModel } from '../models/ReceiptsConsoleModel.js';
|
|
2
|
+
import { sendSuccess, sendError, sendNotFound } from '../utils/response.js';
|
|
3
|
+
const models = new Map();
|
|
4
|
+
function getModel(workspaceDir) {
|
|
5
|
+
let model = models.get(workspaceDir);
|
|
6
|
+
if (!model) {
|
|
7
|
+
model = new ReceiptsConsoleModel(workspaceDir);
|
|
8
|
+
models.set(workspaceDir, model);
|
|
9
|
+
}
|
|
10
|
+
return model;
|
|
11
|
+
}
|
|
12
|
+
/* eslint-disable @typescript-eslint/max-params */
|
|
13
|
+
export async function handleReceiptsRoute(req, res, workspaceDir, subPath) {
|
|
14
|
+
if (req.method !== 'GET') {
|
|
15
|
+
sendError(res, 405, 'method_not_allowed', 'Only GET is supported on /api/v1/receipts');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (subPath === '/counts' || subPath === '/counts/') {
|
|
19
|
+
const model = getModel(workspaceDir);
|
|
20
|
+
try {
|
|
21
|
+
const result = await model.getReceiptCounts();
|
|
22
|
+
sendSuccess(res, result);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
26
|
+
sendError(res, 500, 'receipts_counts_error', message);
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// No regex here: ESLint's prefer-regexp-exec demands .exec(), while the
|
|
31
|
+
// Mimosa write gate flags `.exec(`-shaped calls — plain slicing satisfies both.
|
|
32
|
+
if (subPath.startsWith('/principles/')) {
|
|
33
|
+
const rawId = subPath.slice('/principles/'.length);
|
|
34
|
+
if (rawId.length === 0 || rawId.includes('/')) {
|
|
35
|
+
sendNotFound(res, `Route /api/v1/receipts${subPath} not found`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let principleId;
|
|
39
|
+
try {
|
|
40
|
+
principleId = decodeURIComponent(rawId);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
sendError(res, 400, 'invalid_id', 'Principle ID contains invalid URI encoding');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const model = getModel(workspaceDir);
|
|
47
|
+
try {
|
|
48
|
+
const result = await model.getPrincipleReceipts(principleId);
|
|
49
|
+
sendSuccess(res, result);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
sendError(res, 500, 'receipts_error', message);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
sendNotFound(res, `Route /api/v1/receipts${subPath} not found`);
|
|
58
|
+
}
|
|
59
|
+
export function disposeReceiptsModels() {
|
|
60
|
+
// Models hold no persistent resources (request-scoped readonly connections
|
|
61
|
+
// are closed in finally blocks) — clearing the per-workspace map suffices.
|
|
62
|
+
models.clear();
|
|
63
|
+
}
|
package/console/dist/ui/App.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect, useCallback } from "react";
|
|
3
|
-
import { HashRouter, Routes, Route, Navigate, useNavigate } from "react-router-dom";
|
|
3
|
+
import { HashRouter, Routes, Route, Navigate, useLocation, useNavigate } from "react-router-dom";
|
|
4
4
|
import { I18nextProvider } from "react-i18next";
|
|
5
5
|
import i18n from "./i18n/index.js";
|
|
6
6
|
import { ThemeProvider } from "./components/theme-provider.js";
|
|
@@ -33,7 +33,7 @@ import { getOnboardingState } from "./utils/onboarding-state.js";
|
|
|
33
33
|
const IS_DEV = import.meta.env.DEV;
|
|
34
34
|
function AuthRoutes() {
|
|
35
35
|
const [authed, setAuthed] = useState(null);
|
|
36
|
-
const [showSplash, setShowSplash] = useState(
|
|
36
|
+
const [showSplash, setShowSplash] = useState(() => window.location.hash.startsWith("#/splash"));
|
|
37
37
|
// Onboarding redirect needs workspaceId (for onboarding-state lookup) and
|
|
38
38
|
// feature flags (to gate the redirect). Both are fetched after auth.
|
|
39
39
|
const [currentWorkspaceId, setCurrentWorkspaceId] = useState("default");
|
|
@@ -42,6 +42,7 @@ function AuthRoutes() {
|
|
|
42
42
|
// the onboarding redirect so state isn't saved under a fake "default" key.
|
|
43
43
|
const [workspaceReady, setWorkspaceReady] = useState(false);
|
|
44
44
|
const navigate = useNavigate();
|
|
45
|
+
const location = useLocation();
|
|
45
46
|
const verifyAuth = useCallback(async () => {
|
|
46
47
|
const valid = await checkAuth();
|
|
47
48
|
setAuthed(valid);
|
|
@@ -110,6 +111,8 @@ function AuthRoutes() {
|
|
|
110
111
|
useEffect(() => {
|
|
111
112
|
if (authed !== true || featureFlags === null || showSplash)
|
|
112
113
|
return;
|
|
114
|
+
if (!['/', '/login', '/splash'].includes(location.pathname))
|
|
115
|
+
return;
|
|
113
116
|
const flagEnabled = featureFlags?.new_user_onboarding?.enabled === true;
|
|
114
117
|
// P2-C: if workspace fetch failed, don't force onboarding under "default" key.
|
|
115
118
|
if (flagEnabled && workspaceReady) {
|
|
@@ -119,7 +122,7 @@ function AuthRoutes() {
|
|
|
119
122
|
else {
|
|
120
123
|
navigate('/focus', { replace: true });
|
|
121
124
|
}
|
|
122
|
-
}, [authed, featureFlags, showSplash, currentWorkspaceId, workspaceReady, navigate]);
|
|
125
|
+
}, [authed, featureFlags, showSplash, currentWorkspaceId, workspaceReady, location.pathname, navigate]);
|
|
123
126
|
const handleAuthSuccess = useCallback(() => {
|
|
124
127
|
setAuthed(true);
|
|
125
128
|
// Post-auth redirect is handled by the authed + featureFlags effect above,
|
package/console/dist/ui/api.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ApiResponse } from "../types.js";
|
|
2
2
|
import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm } from "./utils/signal-keywords-api.js";
|
|
3
3
|
import type { OwnerGovernanceView } from '@principles/core/runtime-v2';
|
|
4
|
-
import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData } from "./utils/validators.js";
|
|
4
|
+
import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData, RuleCodeOwnerReviewData, RuleCodeMutationData } from "./utils/validators.js";
|
|
5
5
|
declare function getToken(): string | null;
|
|
6
6
|
declare function setToken(token: string): void;
|
|
7
7
|
declare function clearToken(): void;
|
|
@@ -30,6 +30,39 @@ declare function fetchPrincipleGovernance(principleId: string): Promise<ApiRespo
|
|
|
30
30
|
declare function archivePrinciple(principleId: string): Promise<ApiResponse<unknown>>;
|
|
31
31
|
declare function unarchivePrinciple(principleId: string): Promise<ApiResponse<unknown>>;
|
|
32
32
|
declare function fetchPrincipleTrajectory(principleId: string): Promise<ApiResponse<TrajectoryData>>;
|
|
33
|
+
export interface ReceiptEventData {
|
|
34
|
+
kind: "rule_blocked" | "auto_correct_applied" | "self_reported" | "prompt_injected";
|
|
35
|
+
level: "effect" | "presence";
|
|
36
|
+
sessionId: string | null;
|
|
37
|
+
toolName: string | null;
|
|
38
|
+
filePath: string | null;
|
|
39
|
+
digest: string | null;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
}
|
|
42
|
+
export interface PrincipleReceiptsData {
|
|
43
|
+
status: "ok" | "degraded";
|
|
44
|
+
reason?: string;
|
|
45
|
+
nextAction?: string;
|
|
46
|
+
principleId: string;
|
|
47
|
+
effectCount: number;
|
|
48
|
+
presenceCount: number;
|
|
49
|
+
lastEffectAt: string | null;
|
|
50
|
+
events: ReceiptEventData[];
|
|
51
|
+
}
|
|
52
|
+
export interface ReceiptCountEntryData {
|
|
53
|
+
principleId: string;
|
|
54
|
+
effectCount: number;
|
|
55
|
+
presenceCount: number;
|
|
56
|
+
lastEffectAt: string | null;
|
|
57
|
+
}
|
|
58
|
+
export interface ReceiptCountsData {
|
|
59
|
+
status: "ok" | "degraded";
|
|
60
|
+
reason?: string;
|
|
61
|
+
nextAction?: string;
|
|
62
|
+
counts: ReceiptCountEntryData[];
|
|
63
|
+
}
|
|
64
|
+
declare function fetchPrincipleReceipts(principleId: string): Promise<ApiResponse<PrincipleReceiptsData>>;
|
|
65
|
+
declare function fetchReceiptCounts(): Promise<ApiResponse<ReceiptCountsData>>;
|
|
33
66
|
declare function approveApproval(approvalId: string, note?: string): Promise<ApiResponse<ApprovalRecordData>>;
|
|
34
67
|
declare function rejectApproval(approvalId: string, reason: string): Promise<ApiResponse<ApprovalRecordData>>;
|
|
35
68
|
declare function editApproval(approvalId: string, newArtifactId: string, editReason: string): Promise<ApiResponse<ApprovalRecordData>>;
|
|
@@ -99,6 +132,10 @@ declare function fetchGovernanceQueue(): Promise<ApiResponse<GovernanceQueueData
|
|
|
99
132
|
declare function fetchApprovalsGrouped(): Promise<ApiResponse<ApprovalsGroupedData>>;
|
|
100
133
|
declare function fetchAllActivations(): Promise<ApiResponse<ActivationsData>>;
|
|
101
134
|
declare function disableActivation(activationId: string): Promise<ApiResponse<DisableActivationData>>;
|
|
135
|
+
declare function fetchRuleCodeOwnerReview(activationId: string): Promise<ApiResponse<RuleCodeOwnerReviewData>>;
|
|
136
|
+
declare function ruleCodeDecision(activationId: string, action: 'continue-observing' | 'reject-after-shadow' | 'emergency-deactivate' | 'promote' | 'recover-to-shadow', body: Record<string, unknown>): Promise<ApiResponse<RuleCodeMutationData>>;
|
|
137
|
+
declare function pauseAllRuleCode(body: Record<string, unknown>): Promise<ApiResponse<RuleCodeMutationData>>;
|
|
138
|
+
declare function releaseRuleCodePause(pauseId: string, body: Record<string, unknown>): Promise<ApiResponse<RuleCodeMutationData>>;
|
|
102
139
|
declare function fetchLifecycleMetrics(principleId: string): Promise<ApiResponse<LifecycleMetricsData>>;
|
|
103
140
|
declare function fetchUpdateStatus(): Promise<ApiResponse<UpdateStatusData>>;
|
|
104
141
|
declare function fetchUpdateHistory(): Promise<ApiResponse<UpdateHistoryData>>;
|
|
@@ -158,8 +195,8 @@ export interface FollowUpPayload {
|
|
|
158
195
|
candidateId?: string;
|
|
159
196
|
}
|
|
160
197
|
declare function dispatchFollowUp(decisionId: string, payload: FollowUpPayload): Promise<ApiResponse<FollowUpResponseData>>;
|
|
161
|
-
export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
162
|
-
export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, EvidenceChainRecordData, EvidenceChainStateData, TrajectoryData, TrajectoryStageData, IntentSummaryData, IntentSectionsData, IntentDocWarningData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, LinkCandidateFollowUpData, GuideRulehostFollowUpData, GeneratePatchProposalFollowUpData, IntentVersionEntry, IntentVersionData, } from "./utils/validators.js";
|
|
198
|
+
export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
199
|
+
export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, RuleCodeOwnerReviewData, RuleCodeMutationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, EvidenceChainRecordData, EvidenceChainStateData, TrajectoryData, TrajectoryStageData, IntentSummaryData, IntentSectionsData, IntentDocWarningData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, LinkCandidateFollowUpData, GuideRulehostFollowUpData, GeneratePatchProposalFollowUpData, IntentVersionEntry, IntentVersionData, } from "./utils/validators.js";
|
|
163
200
|
export type { SignalKeyword, PendingSignalTerm } from "./utils/signal-keywords-types.js";
|
|
164
201
|
export type { ActivationRecordData as ActivationRecord } from "./utils/validators.js";
|
|
165
202
|
export type { ApprovalRecordData as ApprovalRecord } from "./utils/validators.js";
|
package/console/dist/ui/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, } from "./utils/signal-keywords-api.js";
|
|
2
|
-
import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, } from "./utils/validators.js";
|
|
2
|
+
import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, validateRuleCodeOwnerReview, validateRuleCodeMutation, } from "./utils/validators.js";
|
|
3
3
|
// ── Auth ──────────────────────────────────────────────────────────────────────
|
|
4
4
|
function getToken() {
|
|
5
5
|
return sessionStorage.getItem("pd_token");
|
|
@@ -136,6 +136,86 @@ async function unarchivePrinciple(principleId) {
|
|
|
136
136
|
async function fetchPrincipleTrajectory(principleId) {
|
|
137
137
|
return request(`/api/principles/${encodeURIComponent(principleId)}/trajectory`, undefined, validateTrajectoryData);
|
|
138
138
|
}
|
|
139
|
+
const RECEIPT_KINDS = new Set(["rule_blocked", "auto_correct_applied", "self_reported", "prompt_injected"]);
|
|
140
|
+
function validateReceiptEvent(value) {
|
|
141
|
+
if (typeof value !== "object" || value === null)
|
|
142
|
+
return null;
|
|
143
|
+
const rec = value;
|
|
144
|
+
if (typeof rec.kind !== "string" || !RECEIPT_KINDS.has(rec.kind))
|
|
145
|
+
return null;
|
|
146
|
+
if (rec.level !== "effect" && rec.level !== "presence")
|
|
147
|
+
return null;
|
|
148
|
+
if (typeof rec.createdAt !== "string")
|
|
149
|
+
return null;
|
|
150
|
+
const asStr = (v) => (typeof v === "string" && v.length > 0 ? v : null);
|
|
151
|
+
return {
|
|
152
|
+
kind: rec.kind,
|
|
153
|
+
level: rec.level,
|
|
154
|
+
sessionId: asStr(rec.sessionId),
|
|
155
|
+
toolName: asStr(rec.toolName),
|
|
156
|
+
filePath: asStr(rec.filePath),
|
|
157
|
+
digest: asStr(rec.digest),
|
|
158
|
+
createdAt: rec.createdAt,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function validatePrincipleReceipts(data) {
|
|
162
|
+
if (typeof data !== "object" || data === null)
|
|
163
|
+
return null;
|
|
164
|
+
const rec = data;
|
|
165
|
+
if (typeof rec.principleId !== "string")
|
|
166
|
+
return null;
|
|
167
|
+
const events = [];
|
|
168
|
+
if (Array.isArray(rec.events)) {
|
|
169
|
+
for (const item of rec.events) {
|
|
170
|
+
const event = validateReceiptEvent(item);
|
|
171
|
+
if (event)
|
|
172
|
+
events.push(event);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
status: rec.status === "ok" ? "ok" : "degraded",
|
|
177
|
+
reason: typeof rec.reason === "string" ? rec.reason : undefined,
|
|
178
|
+
nextAction: typeof rec.nextAction === "string" ? rec.nextAction : undefined,
|
|
179
|
+
principleId: rec.principleId,
|
|
180
|
+
effectCount: typeof rec.effectCount === "number" ? rec.effectCount : 0,
|
|
181
|
+
presenceCount: typeof rec.presenceCount === "number" ? rec.presenceCount : 0,
|
|
182
|
+
lastEffectAt: typeof rec.lastEffectAt === "string" ? rec.lastEffectAt : null,
|
|
183
|
+
events,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function validateReceiptCounts(data) {
|
|
187
|
+
if (typeof data !== "object" || data === null)
|
|
188
|
+
return null;
|
|
189
|
+
const rec = data;
|
|
190
|
+
const counts = [];
|
|
191
|
+
if (Array.isArray(rec.counts)) {
|
|
192
|
+
for (const item of rec.counts) {
|
|
193
|
+
if (typeof item !== "object" || item === null)
|
|
194
|
+
continue;
|
|
195
|
+
const entry = item;
|
|
196
|
+
if (typeof entry.principleId !== "string")
|
|
197
|
+
continue;
|
|
198
|
+
counts.push({
|
|
199
|
+
principleId: entry.principleId,
|
|
200
|
+
effectCount: typeof entry.effectCount === "number" ? entry.effectCount : 0,
|
|
201
|
+
presenceCount: typeof entry.presenceCount === "number" ? entry.presenceCount : 0,
|
|
202
|
+
lastEffectAt: typeof entry.lastEffectAt === "string" ? entry.lastEffectAt : null,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
status: rec.status === "ok" ? "ok" : "degraded",
|
|
208
|
+
reason: typeof rec.reason === "string" ? rec.reason : undefined,
|
|
209
|
+
nextAction: typeof rec.nextAction === "string" ? rec.nextAction : undefined,
|
|
210
|
+
counts,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async function fetchPrincipleReceipts(principleId) {
|
|
214
|
+
return request(`/api/v1/receipts/principles/${encodeURIComponent(principleId)}`, undefined, validatePrincipleReceipts);
|
|
215
|
+
}
|
|
216
|
+
async function fetchReceiptCounts() {
|
|
217
|
+
return request("/api/v1/receipts/counts", undefined, validateReceiptCounts);
|
|
218
|
+
}
|
|
139
219
|
// ── Approvals ─────────────────────────────────────────────────────────────────
|
|
140
220
|
async function approveApproval(approvalId, note) {
|
|
141
221
|
return request('/api/v1/approvals/' + encodeURIComponent(approvalId) + '/approve', {
|
|
@@ -314,6 +394,17 @@ async function disableActivation(activationId) {
|
|
|
314
394
|
body: JSON.stringify({ confirmed: true }),
|
|
315
395
|
}, validateDisableActivation);
|
|
316
396
|
}
|
|
397
|
+
async function fetchRuleCodeOwnerReview(activationId) {
|
|
398
|
+
return request(`/api/v1/activations/${encodeURIComponent(activationId)}/owner-review`, undefined, validateRuleCodeOwnerReview);
|
|
399
|
+
}
|
|
400
|
+
async function mutateRuleCode(path, body) {
|
|
401
|
+
return request(path, { method: 'POST', body: JSON.stringify(body) }, validateRuleCodeMutation);
|
|
402
|
+
}
|
|
403
|
+
function ruleCodeDecision(activationId, action, body) {
|
|
404
|
+
return mutateRuleCode(`/api/v1/activations/${encodeURIComponent(activationId)}/${action}`, body);
|
|
405
|
+
}
|
|
406
|
+
function pauseAllRuleCode(body) { return mutateRuleCode('/api/v1/activations/emergency-pause', body); }
|
|
407
|
+
function releaseRuleCodePause(pauseId, body) { return mutateRuleCode(`/api/v1/activations/emergency-pause/${encodeURIComponent(pauseId)}/release`, body); }
|
|
317
408
|
async function fetchLifecycleMetrics(principleId) {
|
|
318
409
|
return request(`/api/v1/lifecycle/principles/${encodeURIComponent(principleId)}`, undefined, validateLifecycleMetrics);
|
|
319
410
|
}
|
|
@@ -405,6 +496,6 @@ export { request,
|
|
|
405
496
|
// signal-keywords (UI stubs, see signal-keywords-api.ts)
|
|
406
497
|
listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm,
|
|
407
498
|
// auth
|
|
408
|
-
getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport,
|
|
499
|
+
getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport,
|
|
409
500
|
// Feedback submit ladder (Slice 3, spec §8)
|
|
410
|
-
fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
501
|
+
fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|