create-principles-disciple 1.147.6 → 1.147.8
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/_release/product-identity.json +1 -1
- package/core/dist/host/host-installer.d.ts +15 -0
- package/core/dist/host/host-installer.d.ts.map +1 -1
- package/core/dist/host/host-installer.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +2 -2
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-run-correlation.d.ts +1 -1
- package/core/dist/runtime-v2/internalization/artificer-run-correlation.js +1 -1
- package/core/dist/runtime-v2/internalization/consumer-evidence-preflight.d.ts +1 -1
- package/core/dist/runtime-v2/internalization/evidence-readiness.js +1 -1
- package/core/dist/runtime-v2/internalization/owner-evidence-recovery.d.ts +1 -1
- package/core/dist/runtime-v2/pain-recall-capability.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-recall-capability.js +53 -2
- package/core/dist/runtime-v2/pain-recall-capability.js.map +1 -1
- package/core/dist/runtime-v2/pain-recall-read-model.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-recall-read-model.js +60 -5
- package/core/dist/runtime-v2/pain-recall-read-model.js.map +1 -1
- package/core/dist/runtime-v2/principle-reuse/reuse-domain.d.ts +1 -1
- package/core/dist/runtime-v2/principle-reuse/reuse-domain.js +1 -1
- package/core/dist/runtime-v2/principle-reuse/reuse-proposal.d.ts +1 -1
- package/core/dist/runtime-v2/principle-reuse/reuse-proposal.js +1 -1
- package/core/dist/runtime-v2/principle-reuse/reuse-retrieval.d.ts +1 -1
- package/core/dist/runtime-v2/principle-reuse/reuse-retrieval.js +1 -1
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts.map +1 -1
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js +35 -0
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js.map +1 -1
- package/core/dist/runtime-v2/trajectory-schema.d.ts +1 -1
- package/core/package.json +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -29
- package/dist/index.js.map +1 -1
- package/dist/install-summary.d.ts +38 -0
- package/dist/install-summary.d.ts.map +1 -0
- package/dist/install-summary.js +115 -0
- package/dist/install-summary.js.map +1 -0
- package/dist/installer.d.ts +36 -7
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +232 -54
- package/dist/installer.js.map +1 -1
- package/dist/installers/workbuddy-host-installer.d.ts +51 -17
- package/dist/installers/workbuddy-host-installer.d.ts.map +1 -1
- package/dist/installers/workbuddy-host-installer.js +510 -186
- package/dist/installers/workbuddy-host-installer.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/prompts.js.map +1 -1
- package/host-runtime/dist/governance-signal-admission.d.ts +2 -2
- package/host-runtime/dist/governance-signal-admission.js +2 -6
- package/host-runtime/package.json +1 -1
- package/package.json +3 -3
- package/pd-cli/dist/commands/health-mcp.d.ts +19 -0
- package/pd-cli/dist/commands/health-mcp.d.ts.map +1 -1
- package/pd-cli/dist/commands/health-mcp.js +226 -0
- package/pd-cli/dist/commands/health-mcp.js.map +1 -1
- package/pd-cli/dist/commands/health.d.ts.map +1 -1
- package/pd-cli/dist/commands/health.js +18 -1
- package/pd-cli/dist/commands/health.js.map +1 -1
- package/pd-cli/dist/commands/mcp-logs-export.d.ts +7 -0
- package/pd-cli/dist/commands/mcp-logs-export.d.ts.map +1 -0
- package/pd-cli/dist/commands/mcp-logs-export.js +267 -0
- package/pd-cli/dist/commands/mcp-logs-export.js.map +1 -0
- package/pd-cli/dist/commands/workbuddy-worker.d.ts.map +1 -1
- package/pd-cli/dist/commands/workbuddy-worker.js +2 -1
- package/pd-cli/dist/commands/workbuddy-worker.js.map +1 -1
- package/pd-cli/dist/index.js +35 -0
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/zip-writer.d.ts +6 -0
- package/pd-cli/dist/services/zip-writer.d.ts.map +1 -0
- package/pd-cli/dist/services/zip-writer.js +97 -0
- package/pd-cli/dist/services/zip-writer.js.map +1 -0
- package/pd-cli/package.json +1 -1
- package/pd-mcp-server/dist/index.d.ts +1 -0
- package/pd-mcp-server/dist/index.js +167 -10
- package/pd-mcp-server/dist/log-file.d.ts +26 -0
- package/pd-mcp-server/dist/log-file.js +312 -0
- package/pd-mcp-server/dist/logging.d.ts +2 -1
- package/pd-mcp-server/dist/logging.js +25 -14
- package/pd-mcp-server/dist/server.js +78 -24
- package/pd-mcp-server/dist/version.d.ts +1 -1
- package/pd-mcp-server/dist/version.js +1 -1
- package/pd-mcp-server/dist/workspace.d.ts +3 -0
- package/pd-mcp-server/dist/workspace.js +5 -0
- package/pd-mcp-server/package.json +1 -1
- package/plugin/dist/bundle.js +274 -273
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/mcp/launcher.cjs +561 -0
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/dist/installer.js +232 -54
- package/release-manager/dist/installers/workbuddy-host-installer.js +510 -186
- package/release-manager/package.json +1 -1
- package/workbuddy-adapter/dist/pd-hook.js +3 -2
- package/workbuddy-adapter/package.json +1 -1
- package/workbuddy-adapter/plugin/.codebuddy-plugin/plugin.json +1 -1
- package/workbuddy-adapter/plugin/mcp/launcher.cjs +215 -1
- package/workbuddy-adapter/plugin/skills/pd-pain-signal/SKILL.md +4 -0
|
@@ -4,7 +4,8 @@ export type LogLevel = 'info' | 'warn' | 'error';
|
|
|
4
4
|
/** Bound logger: sink fixed at construction, ≤3 params per call. */
|
|
5
5
|
export type LogFn = (level: LogLevel, event: string, fields?: LogFields) => void;
|
|
6
6
|
declare function sanitizeErrorKind(err: unknown): string;
|
|
7
|
-
/** Default stderr sink. One JSON line per event, nothing else.
|
|
7
|
+
/** Default stderr sink. One JSON line per event, nothing else.
|
|
8
|
+
* A closed/broken stderr pipe must never turn into a process-level failure. */
|
|
8
9
|
export declare function stderrSink(line: string): void;
|
|
9
10
|
export declare function createLogger(sink: (line: string) => void, baseFields?: LogFields): LogFn;
|
|
10
11
|
/** Convenience logger bound to stderr (startup/shutdown paths). */
|
|
@@ -16,25 +16,36 @@ function sanitizeErrorKind(err) {
|
|
|
16
16
|
}
|
|
17
17
|
return 'Error';
|
|
18
18
|
}
|
|
19
|
-
/** Default stderr sink. One JSON line per event, nothing else.
|
|
19
|
+
/** Default stderr sink. One JSON line per event, nothing else.
|
|
20
|
+
* A closed/broken stderr pipe must never turn into a process-level failure. */
|
|
20
21
|
export function stderrSink(line) {
|
|
21
|
-
|
|
22
|
+
try {
|
|
23
|
+
process.stderr.write(line + '\n');
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Logging must never affect the service.
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
export function createLogger(sink, baseFields) {
|
|
24
30
|
return (level, event, fields) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
try {
|
|
32
|
+
const entry = {
|
|
33
|
+
ts: new Date().toISOString(),
|
|
34
|
+
server: SERVER_NAME,
|
|
35
|
+
version: SERVER_VERSION,
|
|
36
|
+
level,
|
|
37
|
+
event,
|
|
38
|
+
};
|
|
39
|
+
const merged = { ...baseFields, ...fields };
|
|
40
|
+
for (const [k, v] of Object.entries(merged)) {
|
|
41
|
+
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
|
|
42
|
+
entry[k] = v;
|
|
43
|
+
}
|
|
44
|
+
sink(JSON.stringify(entry));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Logging must never affect the caller (MCP tool calls included).
|
|
36
48
|
}
|
|
37
|
-
sink(JSON.stringify(entry));
|
|
38
49
|
};
|
|
39
50
|
}
|
|
40
51
|
/** Convenience logger bound to stderr (startup/shutdown paths). */
|
|
@@ -16,7 +16,7 @@ import { z } from 'zod';
|
|
|
16
16
|
import { recallPrinciplePainsCapability, } from '@principles/core/runtime-v2/pain-recall-capability';
|
|
17
17
|
import { runWithDeadline, OrphanLimiter, AdmissionLimiter, DEFAULT_DEADLINE_MS } from './deadline.js';
|
|
18
18
|
import { assembleResult, adapterFailureEnvelope, textResult } from './envelope.js';
|
|
19
|
-
import {
|
|
19
|
+
import { withinBudget } from './budget.js';
|
|
20
20
|
import { createLogger, sanitizeErrorKind, stderrSink } from './logging.js';
|
|
21
21
|
import { SERVER_NAME, SERVER_VERSION } from './version.js';
|
|
22
22
|
export const TOOL_NAME = 'pd_recall_principle_pains';
|
|
@@ -56,6 +56,16 @@ function executionFailedResult(message) {
|
|
|
56
56
|
function shuttingDownResult() {
|
|
57
57
|
return executionFailedResult('The server is shutting down; the call was not completed.');
|
|
58
58
|
}
|
|
59
|
+
/** Byte size of the text this call actually returned (never the input). */
|
|
60
|
+
function resultTextBytes(result) {
|
|
61
|
+
try {
|
|
62
|
+
const [first] = result.content;
|
|
63
|
+
return first === undefined ? 0 : Buffer.byteLength(first.text, 'utf8');
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
59
69
|
/**
|
|
60
70
|
* Build the PD MCP server (not yet connected to any transport).
|
|
61
71
|
*
|
|
@@ -87,16 +97,28 @@ export function createPdMcpServer(options) {
|
|
|
87
97
|
// this, N concurrent requests all pass an orphan-count check while none
|
|
88
98
|
// has timed out yet and N > limit capability calls start.
|
|
89
99
|
if (shuttingDown) {
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
const refused = shuttingDownResult();
|
|
101
|
+
log('warn', 'tool_call', {
|
|
102
|
+
toolName: TOOL_NAME,
|
|
103
|
+
durationMs: Date.now() - startedAt,
|
|
104
|
+
status: 'unavailable',
|
|
105
|
+
errorCode: 'shutting_down',
|
|
106
|
+
responseBytes: resultTextBytes(refused),
|
|
107
|
+
truncated: false,
|
|
108
|
+
});
|
|
109
|
+
return refused;
|
|
92
110
|
}
|
|
93
111
|
if (!admissions.tryAcquire()) {
|
|
94
|
-
|
|
112
|
+
const saturated = executionFailedResult('The server is already executing the maximum number of concurrent calls; retry shortly.');
|
|
113
|
+
log('warn', 'tool_call', {
|
|
114
|
+
toolName: TOOL_NAME,
|
|
95
115
|
durationMs: Date.now() - startedAt,
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
status: 'unavailable',
|
|
117
|
+
errorCode: 'saturated',
|
|
118
|
+
responseBytes: resultTextBytes(saturated),
|
|
119
|
+
truncated: false,
|
|
98
120
|
});
|
|
99
|
-
return
|
|
121
|
+
return saturated;
|
|
100
122
|
}
|
|
101
123
|
// The window covers validation → capability → projection →
|
|
102
124
|
// serialization; validation of the parsed input is part of the race.
|
|
@@ -114,8 +136,14 @@ export function createPdMcpServer(options) {
|
|
|
114
136
|
limit: parsed.limit,
|
|
115
137
|
});
|
|
116
138
|
const assembled = assembleResult(envelope);
|
|
117
|
-
if (assembled.ok)
|
|
118
|
-
return {
|
|
139
|
+
if (assembled.ok) {
|
|
140
|
+
return {
|
|
141
|
+
kind: 'envelope',
|
|
142
|
+
result: assembled.result,
|
|
143
|
+
status: envelope.status,
|
|
144
|
+
errorCode: envelope.error?.code ?? 'none',
|
|
145
|
+
};
|
|
146
|
+
}
|
|
119
147
|
return { kind: 'overBudget', bytes: assembled.overBudgetBytes };
|
|
120
148
|
}
|
|
121
149
|
catch (err) {
|
|
@@ -132,36 +160,63 @@ export function createPdMcpServer(options) {
|
|
|
132
160
|
if (outcome.ok) {
|
|
133
161
|
switch (outcome.value.kind) {
|
|
134
162
|
case 'envelope': {
|
|
135
|
-
log('info', '
|
|
163
|
+
log('info', 'tool_call', {
|
|
164
|
+
toolName: TOOL_NAME,
|
|
165
|
+
durationMs,
|
|
166
|
+
status: outcome.value.status,
|
|
167
|
+
errorCode: outcome.value.errorCode,
|
|
168
|
+
responseBytes: resultTextBytes(outcome.value.result),
|
|
169
|
+
truncated: false,
|
|
170
|
+
});
|
|
136
171
|
return outcome.value.result;
|
|
137
172
|
}
|
|
138
173
|
case 'overBudget': {
|
|
139
|
-
log('warn', 'tool_call_over_budget', { durationMs, bytes: outcome.value.bytes, budget: RESPONSE_BUDGET_BYTES });
|
|
140
174
|
const failure = adapterFailureEnvelope('response_budget_exceeded', 'The response exceeded the 32 KiB MCP budget and was withheld without truncation.');
|
|
141
175
|
const failureJson = JSON.stringify(failure);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
176
|
+
// A static shell that cannot fit is a hard defect; surface it in the
|
|
177
|
+
// same tool_call record instead of emitting a second event.
|
|
178
|
+
const failureCode = withinBudget(failureJson)
|
|
179
|
+
? 'response_budget_exceeded'
|
|
180
|
+
: 'failure_envelope_over_budget';
|
|
181
|
+
const withheld = textResult(failureJson, true);
|
|
182
|
+
log('warn', 'tool_call', {
|
|
183
|
+
toolName: TOOL_NAME,
|
|
184
|
+
durationMs,
|
|
185
|
+
status: 'unavailable',
|
|
186
|
+
errorCode: failureCode,
|
|
187
|
+
responseBytes: resultTextBytes(withheld),
|
|
188
|
+
truncated: false,
|
|
189
|
+
});
|
|
190
|
+
return withheld;
|
|
147
191
|
}
|
|
148
192
|
case 'exception': {
|
|
149
193
|
// Sanitized category only — no message, no stack, no paths.
|
|
150
|
-
|
|
151
|
-
|
|
194
|
+
const failed = executionFailedResult('The call failed unexpectedly; the error was logged server-side with a sanitized category only.');
|
|
195
|
+
log('error', 'tool_call', {
|
|
196
|
+
toolName: TOOL_NAME,
|
|
197
|
+
durationMs,
|
|
198
|
+
status: 'unavailable',
|
|
199
|
+
errorCode: 'tool_execution_failed',
|
|
200
|
+
responseBytes: resultTextBytes(failed),
|
|
201
|
+
truncated: false,
|
|
202
|
+
});
|
|
203
|
+
return failed;
|
|
152
204
|
}
|
|
153
205
|
}
|
|
154
206
|
}
|
|
155
207
|
// Deadline exceeded (§4.7): stop waiting, suppress the late result,
|
|
156
208
|
// report an Adapter execution failure. Not underlying cancellation:
|
|
157
209
|
// the capacity slot stays reserved until the orphan settles.
|
|
158
|
-
|
|
210
|
+
const timedOut = executionFailedResult(`The call exceeded the ${deadlineMs} ms deadline; the late result is suppressed and will not be delivered.`);
|
|
211
|
+
log('warn', 'tool_call', {
|
|
212
|
+
toolName: TOOL_NAME,
|
|
159
213
|
durationMs,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
214
|
+
status: 'unavailable',
|
|
215
|
+
errorCode: 'deadline_exceeded',
|
|
216
|
+
responseBytes: resultTextBytes(timedOut),
|
|
217
|
+
truncated: false,
|
|
163
218
|
});
|
|
164
|
-
return
|
|
219
|
+
return timedOut;
|
|
165
220
|
});
|
|
166
221
|
return {
|
|
167
222
|
mcpServer,
|
|
@@ -169,7 +224,6 @@ export function createPdMcpServer(options) {
|
|
|
169
224
|
admissions,
|
|
170
225
|
beginShutdown() {
|
|
171
226
|
shuttingDown = true;
|
|
172
|
-
log('info', 'shutdown_begun', { orphans: orphans.size, active: admissions.active });
|
|
173
227
|
},
|
|
174
228
|
isShuttingDown() {
|
|
175
229
|
return shuttingDown;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* package.json. A unit test pins it to package.json so the two cannot drift.
|
|
8
8
|
*/
|
|
9
9
|
export declare const SERVER_NAME: 'pd-mcp-server';
|
|
10
|
-
export declare const SERVER_VERSION: '0.
|
|
10
|
+
export declare const SERVER_VERSION: '0.3.0';
|
|
11
11
|
/** The only MCP SDK family/version this server is released against
|
|
12
12
|
* (Gate 4-A freeze, PD_MCP_GATE4A_REALITY_CHECK §3). Exact pin — no ranges. */
|
|
13
13
|
export declare const MCP_SDK_PIN: '@modelcontextprotocol/server@2.4.0';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* package.json. A unit test pins it to package.json so the two cannot drift.
|
|
8
8
|
*/
|
|
9
9
|
export const SERVER_NAME = 'pd-mcp-server';
|
|
10
|
-
export const SERVER_VERSION = '0.
|
|
10
|
+
export const SERVER_VERSION = '0.3.0';
|
|
11
11
|
/** The only MCP SDK family/version this server is released against
|
|
12
12
|
* (Gate 4-A freeze, PD_MCP_GATE4A_REALITY_CHECK §3). Exact pin — no ranges. */
|
|
13
13
|
export const MCP_SDK_PIN = '@modelcontextprotocol/server@2.4.0';
|
|
@@ -5,12 +5,15 @@ export interface WorkspaceBinding {
|
|
|
5
5
|
readonly workspaceDir: string;
|
|
6
6
|
readonly host: string | null;
|
|
7
7
|
}
|
|
8
|
+
export type WorkspaceBindingFailureCode = 'workspace_env_missing' | 'workspace_not_absolute' | 'workspace_unreadable' | 'workspace_not_directory' | 'host_invalid';
|
|
8
9
|
export type WorkspaceBindingResolution = {
|
|
9
10
|
readonly ok: true;
|
|
10
11
|
readonly binding: WorkspaceBinding;
|
|
11
12
|
} | {
|
|
12
13
|
readonly ok: false;
|
|
13
14
|
readonly reason: string;
|
|
15
|
+
/** Stable machine-readable code (safe for logs; never a path). */
|
|
16
|
+
readonly reasonCode: WorkspaceBindingFailureCode;
|
|
14
17
|
readonly envVar: string;
|
|
15
18
|
readonly nextAction: string;
|
|
16
19
|
};
|
|
@@ -30,6 +30,7 @@ export function resolveWorkspaceBinding(env) {
|
|
|
30
30
|
return {
|
|
31
31
|
ok: false,
|
|
32
32
|
reason: 'workspace binding env is missing or empty',
|
|
33
|
+
reasonCode: 'workspace_env_missing',
|
|
33
34
|
envVar: WORKSPACE_DIR_ENV,
|
|
34
35
|
nextAction: `Re-run the PD host setup (this writes the PD-owned mcp-binding.json and launches via launcher.cjs). Do not set ${WORKSPACE_DIR_ENV} by hand from agent context.`,
|
|
35
36
|
};
|
|
@@ -38,6 +39,7 @@ export function resolveWorkspaceBinding(env) {
|
|
|
38
39
|
return {
|
|
39
40
|
ok: false,
|
|
40
41
|
reason: 'workspace binding is not an absolute path',
|
|
42
|
+
reasonCode: 'workspace_not_absolute',
|
|
41
43
|
envVar: WORKSPACE_DIR_ENV,
|
|
42
44
|
nextAction: 'Re-run the PD host setup so the binding records the absolute governance workspace directory.',
|
|
43
45
|
};
|
|
@@ -50,6 +52,7 @@ export function resolveWorkspaceBinding(env) {
|
|
|
50
52
|
return {
|
|
51
53
|
ok: false,
|
|
52
54
|
reason: 'workspace binding directory does not exist or is not readable',
|
|
55
|
+
reasonCode: 'workspace_unreadable',
|
|
53
56
|
envVar: WORKSPACE_DIR_ENV,
|
|
54
57
|
nextAction: 'Re-run the PD host setup; if the workspace was moved, re-install PD for this host so the binding is regenerated.',
|
|
55
58
|
};
|
|
@@ -58,6 +61,7 @@ export function resolveWorkspaceBinding(env) {
|
|
|
58
61
|
return {
|
|
59
62
|
ok: false,
|
|
60
63
|
reason: 'workspace binding is not a directory',
|
|
64
|
+
reasonCode: 'workspace_not_directory',
|
|
61
65
|
envVar: WORKSPACE_DIR_ENV,
|
|
62
66
|
nextAction: 'Re-run the PD host setup so the binding points at the governance workspace directory.',
|
|
63
67
|
};
|
|
@@ -68,6 +72,7 @@ export function resolveWorkspaceBinding(env) {
|
|
|
68
72
|
return {
|
|
69
73
|
ok: false,
|
|
70
74
|
reason: 'host marker is not one of the known PD hosts',
|
|
75
|
+
reasonCode: 'host_invalid',
|
|
71
76
|
envVar: HOST_ENV,
|
|
72
77
|
nextAction: 'Re-run the PD host setup; the host marker is written by the PD installer and must not be edited.',
|
|
73
78
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/pd-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Principles Disciple MCP Server — the single shared MCP server implementation for the three PD hosts (Codex, OpenClaw, WorkBuddy). Read-only pain recall through the Gate 3 Capability (SPEC-PD-MCP-GATE4-001).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|