context-mode 1.0.162 → 1.0.164

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 (149) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.openclaw-plugin/openclaw.plugin.json +1 -1
  5. package/.openclaw-plugin/package.json +1 -1
  6. package/README.md +149 -30
  7. package/bin/statusline.mjs +24 -4
  8. package/build/adapters/antigravity/index.d.ts +1 -1
  9. package/build/adapters/antigravity-cli/index.d.ts +51 -0
  10. package/build/adapters/antigravity-cli/index.js +342 -0
  11. package/build/adapters/claude-code/hooks.d.ts +1 -0
  12. package/build/adapters/claude-code/hooks.js +3 -0
  13. package/build/adapters/claude-code/index.js +24 -5
  14. package/build/adapters/client-map.js +5 -0
  15. package/build/adapters/codex/hooks.d.ts +5 -1
  16. package/build/adapters/codex/hooks.js +5 -1
  17. package/build/adapters/codex/index.d.ts +9 -1
  18. package/build/adapters/codex/index.js +87 -5
  19. package/build/adapters/copilot-cli/hooks.d.ts +33 -0
  20. package/build/adapters/copilot-cli/hooks.js +64 -0
  21. package/build/adapters/copilot-cli/index.d.ts +48 -0
  22. package/build/adapters/copilot-cli/index.js +341 -0
  23. package/build/adapters/detect.d.ts +1 -1
  24. package/build/adapters/detect.js +71 -3
  25. package/build/adapters/openclaw/mcp-tools.js +1 -1
  26. package/build/adapters/opencode/index.js +31 -17
  27. package/build/adapters/opencode/zod3tov4.js +27 -6
  28. package/build/adapters/pi/extension.d.ts +2 -12
  29. package/build/adapters/pi/extension.js +128 -109
  30. package/build/adapters/types.d.ts +5 -4
  31. package/build/adapters/types.js +4 -3
  32. package/build/cache-heal.d.ts +48 -0
  33. package/build/cache-heal.js +150 -0
  34. package/build/cli.js +37 -97
  35. package/build/executor.d.ts +25 -0
  36. package/build/executor.js +143 -22
  37. package/build/lifecycle.d.ts +48 -0
  38. package/build/lifecycle.js +111 -0
  39. package/build/opencode-plugin.js +5 -2
  40. package/build/routing-block.d.ts +8 -0
  41. package/build/routing-block.js +86 -0
  42. package/build/runtime.d.ts +0 -36
  43. package/build/runtime.js +107 -27
  44. package/build/search/flood-guard.d.ts +57 -0
  45. package/build/search/flood-guard.js +80 -0
  46. package/build/security.d.ts +73 -3
  47. package/build/security.js +293 -33
  48. package/build/server.d.ts +14 -0
  49. package/build/server.js +441 -354
  50. package/build/session/analytics.d.ts +1 -1
  51. package/build/session/analytics.js +5 -1
  52. package/build/session/db.js +23 -3
  53. package/build/session/extract.js +78 -0
  54. package/build/store.d.ts +1 -1
  55. package/build/store.js +139 -25
  56. package/build/tool-naming.d.ts +4 -0
  57. package/build/tool-naming.js +24 -0
  58. package/build/util/jsonc.d.ts +14 -0
  59. package/build/util/jsonc.js +104 -0
  60. package/cli.bundle.mjs +253 -250
  61. package/configs/antigravity/GEMINI.md +2 -2
  62. package/configs/antigravity-cli/hooks/hooks.json +37 -0
  63. package/configs/antigravity-cli/hooks.json +37 -0
  64. package/configs/antigravity-cli/mcp_config.json +10 -0
  65. package/configs/antigravity-cli/plugin.json +14 -0
  66. package/configs/antigravity-cli/rules/context-mode.md +77 -0
  67. package/configs/antigravity-cli/skills/context-mode/SKILL.md +77 -0
  68. package/configs/claude-code/CLAUDE.md +2 -2
  69. package/configs/codex/AGENTS.md +2 -2
  70. package/configs/copilot-cli/.github/plugin/plugin.json +23 -0
  71. package/configs/copilot-cli/.mcp.json +12 -0
  72. package/configs/copilot-cli/README.md +47 -0
  73. package/configs/copilot-cli/hooks.json +41 -0
  74. package/configs/copilot-cli/skills/context-mode/SKILL.md +38 -0
  75. package/configs/gemini-cli/GEMINI.md +2 -2
  76. package/configs/jetbrains-copilot/copilot-instructions.md +2 -2
  77. package/configs/kilo/AGENTS.md +2 -2
  78. package/configs/kiro/KIRO.md +2 -2
  79. package/configs/omp/SYSTEM.md +2 -2
  80. package/configs/openclaw/AGENTS.md +2 -2
  81. package/configs/opencode/AGENTS.md +2 -2
  82. package/configs/qwen-code/QWEN.md +2 -2
  83. package/configs/vscode-copilot/copilot-instructions.md +2 -2
  84. package/configs/zed/AGENTS.md +2 -2
  85. package/hooks/antigravity-cli/payload.mjs +98 -0
  86. package/hooks/antigravity-cli/posttooluse.mjs +138 -0
  87. package/hooks/antigravity-cli/pretooluse.mjs +78 -0
  88. package/hooks/antigravity-cli/stop.mjs +58 -0
  89. package/hooks/codex/pretooluse.mjs +14 -4
  90. package/hooks/codex/stop.mjs +12 -4
  91. package/hooks/copilot-cli/posttooluse.mjs +79 -0
  92. package/hooks/copilot-cli/precompact.mjs +66 -0
  93. package/hooks/copilot-cli/pretooluse.mjs +41 -0
  94. package/hooks/copilot-cli/sessionstart.mjs +121 -0
  95. package/hooks/copilot-cli/stop.mjs +59 -0
  96. package/hooks/copilot-cli/userpromptsubmit.mjs +77 -0
  97. package/hooks/core/codex-caps.mjs +112 -0
  98. package/hooks/core/formatters.mjs +158 -7
  99. package/hooks/core/mcp-ready.mjs +37 -8
  100. package/hooks/core/routing.mjs +94 -8
  101. package/hooks/core/tool-naming.mjs +3 -0
  102. package/hooks/hooks.json +12 -1
  103. package/hooks/pretooluse.mjs +6 -2
  104. package/hooks/routing-block.mjs +3 -4
  105. package/hooks/security.bundle.mjs +2 -1
  106. package/hooks/session-db.bundle.mjs +5 -5
  107. package/hooks/session-directive.mjs +88 -20
  108. package/hooks/session-extract.bundle.mjs +2 -2
  109. package/hooks/session-helpers.mjs +21 -0
  110. package/hooks/sessionstart.mjs +37 -5
  111. package/hooks/stop.mjs +49 -0
  112. package/openclaw.plugin.json +1 -1
  113. package/package.json +2 -10
  114. package/server.bundle.mjs +206 -200
  115. package/skills/ctx-insight/SKILL.md +12 -17
  116. package/build/util/db-lock.d.ts +0 -65
  117. package/build/util/db-lock.js +0 -166
  118. package/insight/index.html +0 -13
  119. package/insight/package.json +0 -55
  120. package/insight/server.mjs +0 -1265
  121. package/insight/src/components/analytics.tsx +0 -112
  122. package/insight/src/components/ui/badge.tsx +0 -52
  123. package/insight/src/components/ui/button.tsx +0 -58
  124. package/insight/src/components/ui/card.tsx +0 -103
  125. package/insight/src/components/ui/chart.tsx +0 -371
  126. package/insight/src/components/ui/collapsible.tsx +0 -19
  127. package/insight/src/components/ui/input.tsx +0 -20
  128. package/insight/src/components/ui/progress.tsx +0 -83
  129. package/insight/src/components/ui/scroll-area.tsx +0 -55
  130. package/insight/src/components/ui/separator.tsx +0 -23
  131. package/insight/src/components/ui/table.tsx +0 -114
  132. package/insight/src/components/ui/tabs.tsx +0 -82
  133. package/insight/src/components/ui/tooltip.tsx +0 -64
  134. package/insight/src/lib/api.ts +0 -144
  135. package/insight/src/lib/utils.ts +0 -6
  136. package/insight/src/main.tsx +0 -22
  137. package/insight/src/routeTree.gen.ts +0 -189
  138. package/insight/src/router.tsx +0 -19
  139. package/insight/src/routes/__root.tsx +0 -55
  140. package/insight/src/routes/enterprise.tsx +0 -316
  141. package/insight/src/routes/index.tsx +0 -1482
  142. package/insight/src/routes/knowledge.tsx +0 -221
  143. package/insight/src/routes/knowledge_.$dbHash.$sourceId.tsx +0 -137
  144. package/insight/src/routes/search.tsx +0 -97
  145. package/insight/src/routes/sessions.tsx +0 -179
  146. package/insight/src/routes/sessions_.$dbHash.$sessionId.tsx +0 -181
  147. package/insight/src/styles.css +0 -104
  148. package/insight/tsconfig.json +0 -29
  149. package/insight/vite.config.ts +0 -19
@@ -1,29 +1,24 @@
1
1
  ---
2
2
  name: ctx-insight
3
3
  description: |
4
- Open the context-mode Insight analytics dashboard in the browser.
5
- Shows personal metrics: session activity, tool usage, error rate,
6
- parallel work patterns, project focus, and actionable insights.
7
- First run installs dependencies (~30s). Subsequent runs open instantly.
4
+ Open the context-mode Insight dashboard in your default browser.
5
+ Insight is the hosted analytics layer for AI-assisted engineering teams —
6
+ per-engineer productive rate, retry waste, blocker detection, role-narrowed views.
8
7
  Trigger: /context-mode:ctx-insight
9
8
  user-invocable: true
10
9
  ---
11
10
 
12
11
  # Context Mode Insight
13
12
 
14
- Open the personal analytics dashboard in the browser.
13
+ Open the hosted Insight dashboard in the user's default browser.
15
14
 
16
15
  ## Instructions
17
16
 
18
- 1. Call the `ctx_insight` MCP tool (no parameters needed, or pass `port: 4747` to customize). Optional data-dir overrides: `sessionDir`/`insightSessionDir` for `INSIGHT_SESSION_DIR`, and `contentDir`/`insightContentDir` for `INSIGHT_CONTENT_DIR`.
19
- 2. The tool will:
20
- - Copy source files to cache (first run only)
21
- - Install dependencies (first run only, ~30s)
22
- - Build the dashboard (~1s)
23
- - Start a local server
24
- - Open the browser
25
- 3. Display the tool's output to the user it contains progress steps and the dashboard URL.
26
- 4. Tell the user:
27
- - "Dashboard is running at http://localhost:4747"
28
- - "Refresh the page to see updated metrics"
29
- - "Dashboard stops automatically when Claude exits. To stop sooner: kill the PID shown above."
17
+ 1. Call the `ctx_insight` MCP tool (no parameters). It opens
18
+ <https://context-mode.com/insight> in the default browser and returns a
19
+ confirmation line.
20
+ 2. Display the tool's output to the user.
21
+ 3. Tell the user:
22
+ - "Insight opened at https://context-mode.com/insight"
23
+ - The landing page at context-mode.com/insight is the single source of truth for sign-in and pricing details.
24
+ - If the browser did not open automatically, share the URL so they can open it manually.
@@ -1,65 +0,0 @@
1
- /**
2
- * db-lock — Per-DB lockfile primitive for single-writer enforcement (#560).
3
- *
4
- * Issue #560: multiple context-mode MCP servers writing the same on-disk
5
- * SQLite content store unbounded the WAL — readers held shared locks
6
- * indefinitely so `wal_checkpoint(TRUNCATE)` never fired, and the only
7
- * existing truncation path is `closeDB`'s checkpoint on graceful exit
8
- * (which #559's zombie servers never reach). Result: 238MB+ WAL files
9
- * and ctx_search hangs.
10
- *
11
- * This module provides a tiny atomic-write primitive sitting in front of
12
- * `new Database(...)`. The first opener writes its PID into
13
- * `<dbPath>.lock` via O_EXCL (`flag: 'wx'`). Subsequent openers either:
14
- *
15
- * - find the lockfile + see the PID is alive → throw
16
- * DatabaseLockedError with the reporter's verbatim message;
17
- * - find the lockfile + see the PID is dead → claim it, with a re-read
18
- * check to resolve a same-instant race between two stale-claimers.
19
- *
20
- * The lockfile is the PRIMARY single-writer defense. The SQLiteBase ctor
21
- * also applies `locking_mode = EXCLUSIVE` as a SECONDARY defense
22
- * (belt-and-braces) — the lockfile owns the user-facing UX, EXCLUSIVE
23
- * catches the narrow race window between the lockfile check and the
24
- * actual `Database(...)` open.
25
- *
26
- * Per-process tmp DBs (those under `os.tmpdir()`) skip the lockfile
27
- * entirely — those are the existing `defaultDBPath()` shape and embed
28
- * `process.pid` already, so cross-instance contention is impossible.
29
- *
30
- * `isProcessAlive` is COPIED from `store.ts:187` — not imported — to
31
- * keep `db-base.ts` (which imports this module) free of any dependency
32
- * on `store.ts` (which itself imports from `db-base.ts`). See
33
- * PR-559-560-FIX-DESIGN.md regression risks #4.
34
- */
35
- /** User-facing failure used by SQLiteBase to surface the contention. */
36
- export declare class DatabaseLockedError extends Error {
37
- readonly pid: number;
38
- readonly dbPath: string;
39
- constructor(pid: number, dbPath: string);
40
- }
41
- export interface AcquireOptions {
42
- dbPath: string;
43
- }
44
- export interface AcquireResult {
45
- /** True when the lockfile was skipped because dbPath is under tmpdir. */
46
- skipped: boolean;
47
- }
48
- /**
49
- * Atomically claim the lockfile for `dbPath`. Throws `DatabaseLockedError`
50
- * if another live process holds it. Silently claims stale lockfiles whose
51
- * owning PID is dead.
52
- */
53
- export declare function acquireDbLock(opts: AcquireOptions): AcquireResult;
54
- export interface ReleaseOptions {
55
- dbPath: string;
56
- }
57
- /**
58
- * Drop the lockfile for `dbPath`. Swallows all errors so callers can
59
- * always invoke this in a finally / cleanup path without try/catch —
60
- * mirrors the shape of `db-base.ts closeDB`.
61
- *
62
- * Skipped (no-op) when `dbPath` is under tmpdir — symmetric with
63
- * `acquireDbLock`'s skip-gate.
64
- */
65
- export declare function releaseDbLock(opts: ReleaseOptions): void;
@@ -1,166 +0,0 @@
1
- /**
2
- * db-lock — Per-DB lockfile primitive for single-writer enforcement (#560).
3
- *
4
- * Issue #560: multiple context-mode MCP servers writing the same on-disk
5
- * SQLite content store unbounded the WAL — readers held shared locks
6
- * indefinitely so `wal_checkpoint(TRUNCATE)` never fired, and the only
7
- * existing truncation path is `closeDB`'s checkpoint on graceful exit
8
- * (which #559's zombie servers never reach). Result: 238MB+ WAL files
9
- * and ctx_search hangs.
10
- *
11
- * This module provides a tiny atomic-write primitive sitting in front of
12
- * `new Database(...)`. The first opener writes its PID into
13
- * `<dbPath>.lock` via O_EXCL (`flag: 'wx'`). Subsequent openers either:
14
- *
15
- * - find the lockfile + see the PID is alive → throw
16
- * DatabaseLockedError with the reporter's verbatim message;
17
- * - find the lockfile + see the PID is dead → claim it, with a re-read
18
- * check to resolve a same-instant race between two stale-claimers.
19
- *
20
- * The lockfile is the PRIMARY single-writer defense. The SQLiteBase ctor
21
- * also applies `locking_mode = EXCLUSIVE` as a SECONDARY defense
22
- * (belt-and-braces) — the lockfile owns the user-facing UX, EXCLUSIVE
23
- * catches the narrow race window between the lockfile check and the
24
- * actual `Database(...)` open.
25
- *
26
- * Per-process tmp DBs (those under `os.tmpdir()`) skip the lockfile
27
- * entirely — those are the existing `defaultDBPath()` shape and embed
28
- * `process.pid` already, so cross-instance contention is impossible.
29
- *
30
- * `isProcessAlive` is COPIED from `store.ts:187` — not imported — to
31
- * keep `db-base.ts` (which imports this module) free of any dependency
32
- * on `store.ts` (which itself imports from `db-base.ts`). See
33
- * PR-559-560-FIX-DESIGN.md regression risks #4.
34
- */
35
- import { writeFileSync, readFileSync, unlinkSync } from "node:fs";
36
- import { tmpdir } from "node:os";
37
- /** User-facing failure used by SQLiteBase to surface the contention. */
38
- export class DatabaseLockedError extends Error {
39
- pid;
40
- dbPath;
41
- constructor(pid, dbPath) {
42
- super(`Another context-mode server is already running (PID: ${pid}). ` +
43
- `Stop it before starting a new instance.`);
44
- this.name = "DatabaseLockedError";
45
- this.pid = pid;
46
- this.dbPath = dbPath;
47
- }
48
- }
49
- /**
50
- * Liveness probe — a 6-line copy of `store.ts:187 isProcessAlive`.
51
- * Sends signal 0 (no-op kill) which only verifies that the kernel
52
- * recognizes the PID + that the caller has permission to signal it.
53
- *
54
- * Copied (not imported) so this module stays leaf-level and `db-base.ts`
55
- * does not pick up a transitive dependency on `store.ts` — `store.ts`
56
- * already imports from `db-base.ts`, so the reverse would create a
57
- * circular dep that breaks under bun:sqlite's lazy load path.
58
- */
59
- function isProcessAlive(pid) {
60
- try {
61
- process.kill(pid, 0);
62
- return true;
63
- }
64
- catch {
65
- return false;
66
- }
67
- }
68
- function lockPathFor(dbPath) {
69
- return `${dbPath}.lock`;
70
- }
71
- /**
72
- * tmpdir skip-gate — per-process DBs (e.g. defaultDBPath() output) embed
73
- * `process.pid` so cross-instance contention is impossible by
74
- * construction. We never want to install a lockfile on the test runner's
75
- * tmp scratch path either.
76
- */
77
- function isUnderTmpdir(dbPath) {
78
- // Trailing-slash normalize — tmpdir() may or may not include it on the
79
- // current platform, and dbPath may be exactly tmpdir() when callers
80
- // join() with no separator (rare but cheap to guard).
81
- const tmp = tmpdir();
82
- return dbPath === tmp || dbPath.startsWith(tmp + "/") || dbPath.startsWith(tmp + "\\");
83
- }
84
- /**
85
- * Atomically claim the lockfile for `dbPath`. Throws `DatabaseLockedError`
86
- * if another live process holds it. Silently claims stale lockfiles whose
87
- * owning PID is dead.
88
- */
89
- export function acquireDbLock(opts) {
90
- const { dbPath } = opts;
91
- if (isUnderTmpdir(dbPath))
92
- return { skipped: true };
93
- const lockPath = lockPathFor(dbPath);
94
- const ownPid = String(process.pid);
95
- // Fast path: O_EXCL atomic create — succeeds iff the lockfile did not
96
- // exist. This is the single race-free moment that grants ownership.
97
- try {
98
- writeFileSync(lockPath, ownPid, { flag: "wx" });
99
- return { skipped: false };
100
- }
101
- catch (err) {
102
- const code = err?.code;
103
- if (code !== "EEXIST")
104
- throw err;
105
- // Fall through to liveness check.
106
- }
107
- // Slow path: lockfile exists. Read the PID, probe liveness.
108
- let existingPidStr;
109
- try {
110
- existingPidStr = readFileSync(lockPath, "utf-8").trim();
111
- }
112
- catch {
113
- // Lockfile vanished between EEXIST and read — race won by another
114
- // claimer that already finished cleanup. Retry once via the fast
115
- // path; if even that fails, surface as locked (best-effort).
116
- try {
117
- writeFileSync(lockPath, ownPid, { flag: "wx" });
118
- return { skipped: false };
119
- }
120
- catch {
121
- throw new DatabaseLockedError(0, dbPath);
122
- }
123
- }
124
- const existingPid = Number.parseInt(existingPidStr, 10);
125
- if (Number.isFinite(existingPid) && existingPid > 0 && isProcessAlive(existingPid)) {
126
- throw new DatabaseLockedError(existingPid, dbPath);
127
- }
128
- // Stale lockfile — owning PID is dead (or unparseable). Claim it.
129
- // We do NOT use { flag: 'wx' } here because we deliberately want to
130
- // overwrite the dead-PID record. Then re-read to confirm we won the
131
- // race against any other process also seeing the same stale lock.
132
- writeFileSync(lockPath, ownPid, { flag: "w" });
133
- let writtenPid;
134
- try {
135
- writtenPid = Number.parseInt(readFileSync(lockPath, "utf-8").trim(), 10);
136
- }
137
- catch {
138
- // Vanished again — extremely unlikely. Surface as locked rather than
139
- // proceeding with no guarantee.
140
- throw new DatabaseLockedError(0, dbPath);
141
- }
142
- if (writtenPid !== process.pid) {
143
- // Lost the stale-claim race to another concurrent claimer.
144
- throw new DatabaseLockedError(writtenPid, dbPath);
145
- }
146
- return { skipped: false };
147
- }
148
- /**
149
- * Drop the lockfile for `dbPath`. Swallows all errors so callers can
150
- * always invoke this in a finally / cleanup path without try/catch —
151
- * mirrors the shape of `db-base.ts closeDB`.
152
- *
153
- * Skipped (no-op) when `dbPath` is under tmpdir — symmetric with
154
- * `acquireDbLock`'s skip-gate.
155
- */
156
- export function releaseDbLock(opts) {
157
- const { dbPath } = opts;
158
- if (isUnderTmpdir(dbPath))
159
- return;
160
- try {
161
- unlinkSync(lockPathFor(dbPath));
162
- }
163
- catch {
164
- // Already gone, permission denied, etc. — best-effort.
165
- }
166
- }
@@ -1,13 +0,0 @@
1
-
2
- <!doctype html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Context Mode Insight</title>
8
- </head>
9
- <body>
10
- <div id="app"></div>
11
- <script type="module" src="/src/main.tsx"></script>
12
- </body>
13
- </html>
@@ -1,55 +0,0 @@
1
- {
2
- "name": "memory-ui",
3
- "private": true,
4
- "type": "module",
5
- "imports": {
6
- "#/*": "./src/*"
7
- },
8
- "scripts": {
9
- "dev": "vite dev --port 3000",
10
- "build": "vite build",
11
- "preview": "vite preview",
12
- "test": "vitest run"
13
- },
14
- "dependencies": {
15
- "@base-ui/react": "^1.4.0",
16
- "@fontsource-variable/geist": "^5.2.8",
17
- "@tailwindcss/vite": "^4.1.18",
18
- "@tanstack/react-devtools": "latest",
19
- "@tanstack/react-router": "latest",
20
- "@tanstack/react-router-devtools": "latest",
21
- "@tanstack/router-plugin": "^1.132.0",
22
- "class-variance-authority": "^0.7.1",
23
- "clsx": "^2.1.1",
24
- "lucide-react": "^0.545.0",
25
- "react": "^19.2.0",
26
- "react-dom": "^19.2.0",
27
- "recharts": "^3.8.1",
28
- "shadcn": "^4.2.0",
29
- "tailwind-merge": "^3.5.0",
30
- "tailwindcss": "^4.1.18",
31
- "tw-animate-css": "^1.4.0",
32
- "better-sqlite3": "^12.0.0"
33
- },
34
- "devDependencies": {
35
- "@tailwindcss/typography": "^0.5.16",
36
- "@tanstack/devtools-vite": "latest",
37
- "@tanstack/router-plugin": "latest",
38
- "@testing-library/dom": "^10.4.1",
39
- "@testing-library/react": "^16.3.0",
40
- "@types/node": "^22.10.2",
41
- "@types/react": "^19.2.0",
42
- "@types/react-dom": "^19.2.0",
43
- "@vitejs/plugin-react": "^6.0.1",
44
- "jsdom": "^28.1.0",
45
- "typescript": "^5.7.2",
46
- "vite": "^8.0.0",
47
- "vitest": "^3.0.5"
48
- },
49
- "pnpm": {
50
- "onlyBuiltDependencies": [
51
- "esbuild",
52
- "lightningcss"
53
- ]
54
- }
55
- }