@prodero/curator 0.0.0-stage → 0.2.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.
Files changed (148) hide show
  1. package/ARCHITECTURE.md +298 -0
  2. package/CHANGELOG.md +33 -0
  3. package/CONTRIBUTING.md +9 -0
  4. package/LICENSE +21 -0
  5. package/README.md +93 -2
  6. package/SECURITY.md +7 -0
  7. package/bin/prodero +7 -0
  8. package/dist/cli.js +266 -0
  9. package/dist/context-instructions.js +2 -0
  10. package/dist/contracts.js +51 -0
  11. package/dist/conversation-presentation.js +297 -0
  12. package/dist/core/agent-instructions.js +52 -0
  13. package/dist/core/applicability-label.js +11 -0
  14. package/dist/core/applicability.js +143 -0
  15. package/dist/core/bootstrap.js +129 -0
  16. package/dist/core/consolidation.js +315 -0
  17. package/dist/core/constants.js +21 -0
  18. package/dist/core/context-allocation.js +54 -0
  19. package/dist/core/context-snapshot.js +12 -0
  20. package/dist/core/context.js +489 -0
  21. package/dist/core/curation-clauses.js +68 -0
  22. package/dist/core/curation-evidence.js +98 -0
  23. package/dist/core/curation-graphical.js +117 -0
  24. package/dist/core/curation-question.js +28 -0
  25. package/dist/core/curation-review-presentation.js +4 -0
  26. package/dist/core/curation-review-state.js +62 -0
  27. package/dist/core/curation-review.js +573 -0
  28. package/dist/core/curation-revision.js +106 -0
  29. package/dist/core/curation-semantic-contract.js +242 -0
  30. package/dist/core/curation-semantic-jobs.js +340 -0
  31. package/dist/core/diagnostics.js +17 -0
  32. package/dist/core/format.js +114 -0
  33. package/dist/core/ids.js +6 -0
  34. package/dist/core/imports.js +169 -0
  35. package/dist/core/index.js +93 -0
  36. package/dist/core/instruction-review.js +86 -0
  37. package/dist/core/integrity-files.js +174 -0
  38. package/dist/core/intelligence.js +95 -0
  39. package/dist/core/knowledge-analysis.js +46 -0
  40. package/dist/core/knowledge-authority.js +143 -0
  41. package/dist/core/knowledge-curation.js +316 -0
  42. package/dist/core/knowledge-engine.js +475 -0
  43. package/dist/core/knowledge-graph.js +192 -0
  44. package/dist/core/knowledge-lifecycle.js +212 -0
  45. package/dist/core/knowledge-management.js +113 -0
  46. package/dist/core/knowledge-migration.js +84 -0
  47. package/dist/core/knowledge-policy.js +38 -0
  48. package/dist/core/knowledge-provenance.js +90 -0
  49. package/dist/core/knowledge-write-policy.js +85 -0
  50. package/dist/core/language.js +14 -0
  51. package/dist/core/local-preferences.js +76 -0
  52. package/dist/core/matching.js +6 -0
  53. package/dist/core/memory-index.js +241 -0
  54. package/dist/core/memory-intelligence.js +288 -0
  55. package/dist/core/memory-link-repair.js +70 -0
  56. package/dist/core/memory-operations.js +122 -0
  57. package/dist/core/memory-pressure.js +212 -0
  58. package/dist/core/memory-sync-curator.js +82 -0
  59. package/dist/core/memory-sync.js +558 -0
  60. package/dist/core/memory-transformation-bundle.js +163 -0
  61. package/dist/core/memory-transformation-proposal.js +135 -0
  62. package/dist/core/memory-transformation.js +108 -0
  63. package/dist/core/memory.js +186 -0
  64. package/dist/core/migrations.js +569 -0
  65. package/dist/core/npm-update.js +289 -0
  66. package/dist/core/path-scope.js +27 -0
  67. package/dist/core/plugin-files.js +116 -0
  68. package/dist/core/project-root.js +39 -0
  69. package/dist/core/project.js +634 -0
  70. package/dist/core/promotion.js +279 -0
  71. package/dist/core/reconciliation.js +61 -0
  72. package/dist/core/secrets.js +67 -0
  73. package/dist/core/semantic-safety.js +33 -0
  74. package/dist/core/session-index.js +116 -0
  75. package/dist/core/session-review.js +150 -0
  76. package/dist/core/sessions.js +289 -0
  77. package/dist/core/settings.js +94 -0
  78. package/dist/core/skill-curation.js +239 -0
  79. package/dist/core/skill-polish.js +41 -0
  80. package/dist/core/skills.js +387 -0
  81. package/dist/core/storage.js +462 -0
  82. package/dist/core/sync-transaction.js +290 -0
  83. package/dist/core/telemetry.js +64 -0
  84. package/dist/core/templates.js +53 -0
  85. package/dist/core/types.js +2 -0
  86. package/dist/core/update.js +326 -0
  87. package/dist/curation-review-adapter.js +92 -0
  88. package/dist/diagnostic-boundary.js +55 -0
  89. package/dist/filesystem/permissions.js +39 -0
  90. package/dist/hosts/adapters.js +119 -0
  91. package/dist/hosts/files.js +133 -0
  92. package/dist/hosts/manager.js +150 -0
  93. package/dist/hosts/public-entry.js +47 -0
  94. package/dist/hosts/runtime-command.js +66 -0
  95. package/dist/hosts/runtime.js +139 -0
  96. package/dist/hosts/wizard.js +114 -0
  97. package/dist/knowledge-table.js +38 -0
  98. package/dist/mcp-development.js +69 -0
  99. package/dist/mcp-workspace.js +141 -0
  100. package/dist/memory-presentation.js +182 -0
  101. package/dist/memory-sync-operation.js +88 -0
  102. package/dist/plugins/api.js +2 -0
  103. package/dist/plugins/context.js +20 -0
  104. package/dist/plugins/mcp.js +72 -0
  105. package/dist/plugins/registry.js +106 -0
  106. package/dist/presentation-cards.js +32 -0
  107. package/dist/presentation-server.js +94 -0
  108. package/dist/presentation-trace.js +174 -0
  109. package/dist/presentation.js +443 -0
  110. package/dist/providers/mcp-sampling.js +45 -0
  111. package/dist/server.js +664 -0
  112. package/dist/settings-definition.js +22 -0
  113. package/dist/skill-instructions.js +2 -0
  114. package/dist/status-presentation.js +20 -0
  115. package/dist/text-layout.js +278 -0
  116. package/dist/update-command.js +53 -0
  117. package/dist/update-instructions.js +4 -0
  118. package/dist-ui/index.html +216 -0
  119. package/docs/APPLICABILITY.md +151 -0
  120. package/docs/COMPATIBILITY.md +68 -0
  121. package/docs/CONTEXT-SELECTION-V2.md +61 -0
  122. package/docs/CURATION-APP-REVIEW.md +156 -0
  123. package/docs/CURATION-CLAUSE-REFINEMENT.md +45 -0
  124. package/docs/IMPORTER-CURATION.md +142 -0
  125. package/docs/KNOWLEDGE-AUTHORITY.md +165 -0
  126. package/docs/KNOWLEDGE-SCHEMA-V2.md +150 -0
  127. package/docs/MIGRATIONS.md +103 -0
  128. package/docs/PRIVACY.md +28 -0
  129. package/docs/RECOVERY.md +58 -0
  130. package/docs/RELEASING.md +98 -0
  131. package/docs/hosts.md +152 -0
  132. package/docs/images/prodero-context-ready-cropped.png +0 -0
  133. package/docs/images/prodero-overview-cropped.png +0 -0
  134. package/docs/images/prodero-session-learned-cropped.png +0 -0
  135. package/docs/plugins.md +83 -0
  136. package/docs/ui-themes.md +49 -0
  137. package/instructions/AGENTS.md +39 -0
  138. package/package.json +92 -4
  139. package/plugins/migrate_ai_studio/README.md +101 -0
  140. package/plugins/migrate_ai_studio/index.cjs +396 -0
  141. package/plugins/migrate_ai_studio/instructions/audit.md +25 -0
  142. package/plugins/migrate_ai_studio/instructions/classify.md +41 -0
  143. package/plugins/migrate_ai_studio/instructions/migrate.md +34 -0
  144. package/plugins/migrate_ai_studio/instructions/verify.md +20 -0
  145. package/plugins/migrate_ai_studio/plugin.json +11 -0
  146. package/plugins/migrate_ai_studio/schema.cjs +20 -0
  147. package/plugins/migrate_ai_studio/ui/dist/index.html +77 -0
  148. package/prodero.release.json +5 -0
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ import { DEFAULT_CONTEXT_BUDGET_TOKENS } from './core/telemetry.js';
3
+ export const THEMES = [
4
+ { id: 'prodero', label: 'Current / Prodero', swatch: '#c6ff76', base: '#0b0d0c' },
5
+ { id: 'dark-neon', label: 'Dark Neon', swatch: '#b6efff', base: '#020304' },
6
+ { id: 'pink-neon', label: 'Pink Neon', swatch: '#ff63c5', base: '#090307' },
7
+ { id: 'blue-neon', label: 'Blue Neon', swatch: '#55c9ff', base: '#020710' },
8
+ { id: 'purple-neon', label: 'Purple Neon', swatch: '#b98aff', base: '#07030e' },
9
+ { id: 'light', label: 'Light', swatch: '#3e6516', base: '#f7f9fc' },
10
+ { id: 'system', label: 'System', swatch: '#a0adbd', base: '#f7f9fc' },
11
+ ];
12
+ export const modeSchema = z.enum(['auto', 'ui', 'text']);
13
+ export const themeSchema = z.enum(['prodero', 'dark-neon', 'pink-neon', 'blue-neon', 'purple-neon', 'light', 'system']);
14
+ export const presentationConfigSchema = z.object({ mode: modeSchema.optional(), theme: themeSchema.optional() }).passthrough();
15
+ export const SETTINGS = [
16
+ { key: 'presentation.mode', group: 'Presentation', label: 'Display mode', description: 'Choose automatic display, interactive UI, or text on this checkout.', type: 'enum', defaultValue: 'auto', options: [{ id: 'auto', label: 'Automatic', description: 'Use MCP Apps when advertised, otherwise readable text.' }, { id: 'ui', label: 'UI', description: 'Prefer the interactive Prodero application on this checkout.' }, { id: 'text', label: 'Text', description: 'Use readable text on this checkout.' }], validation: modeSchema },
17
+ { key: 'presentation.theme', group: 'Presentation', label: 'Theme', description: 'Visual theme used by Prodero on this checkout.', type: 'enum', defaultValue: 'prodero', options: THEMES, validation: themeSchema },
18
+ { key: 'context.max_tokens', group: 'Context', label: 'Task context budget', description: 'Maximum Prodero context budget prepared for a task.', type: 'integer', defaultValue: DEFAULT_CONTEXT_BUDGET_TOKENS, unit: 'tokens', min: 1, max: 1000000, validation: z.number().int().min(1).max(1000000) },
19
+ ];
20
+ export const settingKeySchema = z.enum(['presentation.mode', 'presentation.theme', 'context.max_tokens']);
21
+ export const SETTINGS_ROUTING = 'For requests to show Prodero settings, project settings, or Prodero config, call prodero_config_get and show its friendly settings view. For project preference changes use prodero_config_set: text-only/text mode → presentation.mode=text; switch back to UI → presentation.mode=ui; automatic presentation → presentation.mode=auto; blue/purple neon → presentation.theme=blue-neon/purple-neon; context budget 8000 → context.max_tokens=8000. Display mode/theme are ignored checkout-local preferences; context budget remains shared project configuration. Legacy project presentation defaults remain fallback. Use reset:true without value to remove only the requested local presentation override. Never store settings as knowledge. Resolve the current project on each call. Read effective settings when choosing the text gateway; do not rely on a previous project or conversational preference.';
22
+ //# sourceMappingURL=settings-definition.js.map
@@ -0,0 +1,2 @@
1
+ export const SKILL_EXECUTION_ROUTING = "For agent skill discovery or procedure retrieval during task execution, use prodero_skills_read without opening UI. Reuse skill procedures already supplied by Prepare. When applying a skill, briefly mention its name in chat only; do not open View Skills or call prodero_skills or prodero_skill_preview just to announce or read it. Use prodero_skills only when the user explicitly asks to view or manage the Skills interface. Candidate review still uses prodero_skill_preview on user intent.";
2
+ //# sourceMappingURL=skill-instructions.js.map
@@ -0,0 +1,20 @@
1
+ import { publicDiagnostic } from './core/diagnostics.js';
2
+ import { PRODERO_VERSION } from './core/constants.js';
3
+ import { MEMORY_COPY } from './memory-presentation.js';
4
+ const plain = (value) => value.replace(/[\u0000-\u001f\u007f-\u009f]/g, ' ').trim();
5
+ export function statusFailure(error, scope, migration) {
6
+ const message = plain(publicDiagnostic(error)), code = /^(PRODERO_[A-Z0-9_]+):/.exec(message)?.[1] ?? 'PRODERO_STATUS_FAILED';
7
+ return { ok: false, version: PRODERO_VERSION, scope, error: { code, message, recovery: migration ? plain(publicDiagnostic(migration.recovery ?? (migration.state === 'runtime-too-old' ? 'Update Curator before reading this project.' : 'Run prodero migrate status with this project root to review the required update.'))) : 'Check the command arguments, selected root, and preserved configuration before retrying.' }, ...(migration ? { migration: { ...migration, ...(migration.diagnostic ? { diagnostic: plain(publicDiagnostic(migration.diagnostic)) } : {}), ...(migration.recovery ? { recovery: plain(publicDiagnostic(migration.recovery)) } : {}) } } : {}) };
8
+ }
9
+ export function renderStatusFailure(result) {
10
+ return [`Prodero ${result.version} · ${result.scope} status unavailable`, `${result.error.code}: ${result.error.message}`, result.error.recovery, ...(result.migration ? [`Project update: ${result.migration.state}`] : [])].join('\n');
11
+ }
12
+ const yes = (value) => value === null ? 'unknown' : value ? 'yes' : 'no';
13
+ export function renderMachineStatus(result) {
14
+ return [`Prodero ${result.version}`, `Machine integrations${result.ok ? '' : ' · attention required'}`, ...result.hosts.flatMap(h => [`${h.name}: ${h.state.replaceAll('-', ' ')}`, ` Detected: ${yes(h.detected)} · MCP configured: ${yes(h.mcpConfigured)} · Launcher installed: ${yes(h.launcherInstalled)}${h.runtimeMode ? ` · Runtime: ${h.runtimeMode}` : ''}`, ` ${plain(publicDiagnostic(h.message))}`])].join('\n');
15
+ }
16
+ export function renderProjectStatus(result) {
17
+ const p = result.project, u = result.update;
18
+ return [`Prodero ${result.version}`, `Project: ${plain(p.name)} (${plain(p.root)})`, `Initialized: ${yes(p.initialized)} · Git repository: ${yes(p.git)} · Project instructions: ${yes(p.agentsFile)}`, ...(p.initialized ? [`Project schema: ${p.schemaVersion}`, `Knowledge: ${p.knowledgeCount} current · ${p.localKnowledgeCount} Local · ${p.versionedKnowledgeCount} Versioned`, `Sessions: ${p.sessionCount} total · ${p.activeSessionCount} active · ${p.pendingSessionCount} pending`, `Skills: ${p.skillCount} active · ${p.skillCandidateCount} candidates`, `Checkpoints: ${p.checkpointCount} · Last sync: ${p.lastSyncAt ?? 'never'}`, `Needs attention: ${p.conflictCount} conflicts · ${p.knowledgeGraph.brokenReferences} broken references · ${p.promotionRecommendedCount} sharing suggestions`].concat(p.memoryHealth?.missingProvenanceItems ? [`Provenance: ${p.memoryHealth.missingProvenanceItems} current records with incomplete metadata. ${MEMORY_COPY.incompleteProvenance}`] : []) : ['Project is not initialized. Run prodero init with --root set to this directory.']), u.status === 'current' ? `Update: current (${u.current})` : u.status === 'update-available' ? `Update available: ${u.current} → ${u.latest}` : `Update check ${u.status}: ${plain(publicDiagnostic(u.error ?? 'No release information is available.'))}`, ...(u.status === 'update-available' && u.manualUpdateCommand ? [u.manualUpdateCommand] : [])].join('\n');
19
+ }
20
+ //# sourceMappingURL=status-presentation.js.map
@@ -0,0 +1,278 @@
1
+ import { numberedActions } from './conversation-presentation.js';
2
+ const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
3
+ const graphemes = (s) => Array.from(segmenter.segment(s), x => x.segment);
4
+ const glyphWidth = (s) => {
5
+ const n = s.codePointAt(0) ?? 0;
6
+ if (/^[\p{Mark}]+$/u.test(s))
7
+ return 0;
8
+ return /[\p{Extended_Pictographic}\p{Regional_Indicator}\u20e3]/u.test(s) || n >= 0x1100 && (n <= 0x115f || n >= 0x2e80 && n <= 0xa4cf || n >= 0xac00 && n <= 0xd7a3 || n >= 0xf900 && n <= 0xfaff || n >= 0xfe10 && n <= 0xfe6f || n >= 0xff01 && n <= 0xff60 || n >= 0x20000 && n <= 0x3ffff) ? 2 : 1;
9
+ };
10
+ export const textWidth = (s) => graphemes(s).reduce((n, g) => n + glyphWidth(g), 0);
11
+ // Formatting never permits terminal escapes, bidi controls or injected fence endings.
12
+ // Newlines and literal code/body spacing survive in the verbatim fallback below.
13
+ export const safeText = (s) => String(s ?? '').replace(/\x1b(?:\][^\x07]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])/g, '').replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, '');
14
+ export function wrapText(raw, width) {
15
+ const result = [];
16
+ for (const paragraph of safeText(raw).replace(/\t/g, ' ').split(/\r?\n/)) {
17
+ let line = '', used = 0;
18
+ for (const g of graphemes(paragraph)) {
19
+ const size = glyphWidth(g);
20
+ if (used + size > width && line) {
21
+ const cut = line.lastIndexOf(' ');
22
+ if (cut > 0) {
23
+ result.push(line.slice(0, cut));
24
+ line = line.slice(cut + 1);
25
+ used = textWidth(line);
26
+ }
27
+ else {
28
+ result.push(line);
29
+ line = '';
30
+ used = 0;
31
+ }
32
+ }
33
+ line += g;
34
+ used += size;
35
+ }
36
+ result.push(line);
37
+ }
38
+ return result;
39
+ }
40
+ /** Dynamic fences retain complete Markdown/code examples without escaping their wording. */
41
+ export function textFence(content) {
42
+ const text = safeText(content);
43
+ let longest = 2;
44
+ for (const m of text.matchAll(/`+/g))
45
+ longest = Math.max(longest, m[0].length);
46
+ const fence = '`'.repeat(longest + 1);
47
+ return `${fence}text\n${text}\n${fence}`;
48
+ }
49
+ export function entryKey(index) {
50
+ let n = index + 1, key = '';
51
+ do {
52
+ n--;
53
+ key = String.fromCharCode(65 + n % 26) + key;
54
+ n = Math.floor(n / 26);
55
+ } while (n);
56
+ return key;
57
+ }
58
+ const number = (n) => n.toLocaleString('en-US');
59
+ export function budgetLines(b) {
60
+ if (!Number.isFinite(b.used) || !Number.isFinite(b.total) || b.used < 0 || b.total <= 0)
61
+ return ['Budget unavailable.'];
62
+ const percent = Math.round(b.used / b.total * 100);
63
+ const filled = Math.max(0, Math.min(25, Math.round(b.used / b.total * 25)));
64
+ return ['▰'.repeat(filled) + '▱'.repeat(25 - filled) + ` ${percent}%`, `${number(b.used)} / ${number(b.total)} est. tokens`, `${b.source} · Prodero allocation only.`, ...(b.used > b.total ? ['Allocation exceeds its budget.'] : [])];
65
+ }
66
+ export function renderProductText(vm, diagnostics = false, expanded = diagnostics, plain = false) {
67
+ const scene = vm.textScene, action = scene?.action, v = vm.conversation;
68
+ const width = 38, prefix = plain ? '| ' : '│ ', rule = plain ? '-' : '─';
69
+ const screens = { open: '01', status: '01', 'status-details': '01', initialized: '01', knowledge: '02', 'knowledge-mutated': '02', prepare: '03', context: '03', 'memory-sync': '04', 'curation-question': '04', curation: '05', 'instruction-review': '06', 'instruction-optimize': '06', 'promotion-preview': '07', 'promotion-applied': '07', 'session-close': '08', 'session-review': '08', 'config-get': '09', 'update-instructions': '10', migration: '10', error: '00' };
70
+ const screen = vm.knowledgeTable ? '02' : screens[action ?? ''] ?? '00';
71
+ const head = `${plain ? '+-' : '╭─'} >_ PRODERO `;
72
+ const lines = [head + rule.repeat(width - textWidth(head) - 4) + ` /${screen}`];
73
+ const line = (text = '') => {
74
+ const indent = (text.match(/^ +/)?.[0] ?? '').slice(0, 12);
75
+ lines.push(...wrapText(text.slice(indent.length), width - 2 - indent.length).map(s => prefix.trimEnd() + (s.trimEnd() ? ' ' + indent + s.trimEnd() : '')));
76
+ };
77
+ const section = (title) => {
78
+ if (textWidth(safeText(title)) > width - 5) {
79
+ lines.push((plain ? '+' : '├') + rule.repeat(width - 1));
80
+ line(title);
81
+ return;
82
+ }
83
+ const parts = wrapText(title, width - 5);
84
+ const p = `${plain ? '+-' : '├─'} ${parts.shift()} `;
85
+ lines.push(p + rule.repeat(Math.max(0, width - textWidth(p))));
86
+ parts.forEach(part => line(part));
87
+ };
88
+ const inset = () => { line(); lines.push(prefix + ' ' + rule.repeat(27)); line(); };
89
+ const title = vm.title.replace(/^Prodero · /, '');
90
+ line(action === 'update-instructions' ? 'Prodero · terminal update' : scene?.project ? `${scene.project} · project memory` : 'Prodero');
91
+ line();
92
+ const prepared = action === 'prepare' || action === 'context';
93
+ const full = expanded || !v || v.kind === 'details';
94
+ const compactReady = prepared && !full && !v?.blocking && !v?.attention.length;
95
+ if (compactReady) {
96
+ const compact = ['>_ PRODERO /03 · Context Ready'];
97
+ if (scene?.project)
98
+ compact.push(...wrapText(scene.project, width));
99
+ compact.push(...wrapText(v?.facts.find(x => x.includes(' required · ')) ?? '', width));
100
+ if (scene?.budget)
101
+ compact.push(...wrapText(`${number(scene.budget.used)} / ${number(scene.budget.total)} est. Prodero tokens`, width));
102
+ compact.push('Ready · continuing the task');
103
+ return textFence(compact.join('\n'));
104
+ }
105
+ // Exact bodies are deliberately unframed: long code/paths and whitespace are not
106
+ // truncated or rewritten merely to fit a phone. The panel remains bounded.
107
+ const bodies = [];
108
+ const verbatim = (heading, items) => {
109
+ if (!items.length)
110
+ return;
111
+ bodies.push(`${heading}:\n` + items.map(i => [i.title, i.body, ...i.notes].filter(Boolean).join('\n')).join('\n\n ' + rule.repeat(27) + '\n\n'));
112
+ };
113
+ if (scene?.home && !full) {
114
+ const h = scene.home;
115
+ if (h.initialized) {
116
+ if (action === 'initialized') {
117
+ line('Initialized');
118
+ line();
119
+ }
120
+ section('CONTEXT');
121
+ if (scene.budget)
122
+ budgetLines(scene.budget).forEach(x => line(plain ? x.replaceAll('▰', '#').replaceAll('▱', '.') : x));
123
+ else
124
+ line('Task allocation not prepared here.');
125
+ line();
126
+ section('MEMORY');
127
+ if (h.records !== undefined)
128
+ line(`${number(h.records)} records`);
129
+ if (h.local !== undefined && h.versioned !== undefined)
130
+ line(`${number(h.local)} local · ${number(h.versioned)} versioned`);
131
+ line();
132
+ section('ATTENTION');
133
+ if (h.deferred !== undefined)
134
+ line(`? ${h.deferred} deferred questions`);
135
+ if (h.pending !== undefined)
136
+ line(`Δ ${h.pending} unapplied change groups`);
137
+ (v?.attention ?? []).forEach(x => line(x));
138
+ if (!v?.attention.length && h.deferred === undefined && h.pending === undefined)
139
+ line(action === 'status' && h.records === undefined ? 'Lightweight status; counts not loaded.' : 'No attention needed.');
140
+ // Session activity is real data, not evidence of a background agent.
141
+ v?.facts.filter(x => x.startsWith('Session')).forEach(x => line(x));
142
+ }
143
+ else {
144
+ section(v?.state ?? title);
145
+ (v?.facts ?? vm.notices).forEach(x => line(x));
146
+ v?.attention.forEach(x => line(x));
147
+ }
148
+ }
149
+ else if (prepared) {
150
+ section(v?.blocking ? v.state : v?.attention.length ? 'Attention' : action === 'prepare' ? 'Context Ready' : 'View Context');
151
+ if (!compactReady && scene?.task)
152
+ line(`Task: ${scene.task}`);
153
+ if (!v?.blocking)
154
+ line(action === 'context' ? 'Read-only context view.' : v?.attention.length ? 'Task is not blocked; see attention.' : 'Ready · continuing the task');
155
+ const facts = v?.facts.filter(x => !x.startsWith('Context ')) ?? [];
156
+ if (!compactReady) {
157
+ line();
158
+ section('PROVIDED TO AGENT');
159
+ }
160
+ facts.forEach(x => line(x));
161
+ if (scene?.budget) {
162
+ if (!compactReady) {
163
+ line();
164
+ section('PRODERO CONTEXT');
165
+ budgetLines(scene.budget).forEach(x => line(plain ? x.replaceAll('▰', '#').replaceAll('▱', '.') : x));
166
+ }
167
+ else
168
+ line(`${number(scene.budget.used)} / ${number(scene.budget.total)} est. Prodero tokens`);
169
+ }
170
+ if (v?.attention.length) {
171
+ line();
172
+ section('ATTENTION');
173
+ v.attention.forEach(x => line(x));
174
+ }
175
+ if (full)
176
+ for (const s of vm.sections) {
177
+ section(s.title);
178
+ s.items.forEach((i, index) => { if (index)
179
+ inset(); line(i.title); });
180
+ verbatim(s.title, s.items);
181
+ }
182
+ }
183
+ else if (vm.knowledgeTable) {
184
+ const t = vm.knowledgeTable;
185
+ section('KNOWLEDGE');
186
+ line(t.rows.length ? `Showing ${t.offset + 1}-${t.offset + t.rows.length} of ${t.total}` : 'No knowledge matches these filters.');
187
+ t.rows.forEach((r, index) => {
188
+ if (index)
189
+ inset();
190
+ else
191
+ line();
192
+ line(`${r.key} · ${r.title}`);
193
+ line(` ${r.layer}`);
194
+ const preview = vm.sections.find(s => s.title === 'Knowledge')?.items[index]?.body;
195
+ if (preview) {
196
+ const flat = safeText(preview).replace(/\s+/g, ' ').trim();
197
+ const summary = graphemes(flat).slice(0, 90).join('');
198
+ line(' ' + summary + (summary.length < flat.length ? '…' : ''));
199
+ }
200
+ });
201
+ if (t.rows.length) {
202
+ line();
203
+ line('Enter a letter to open its record.');
204
+ }
205
+ if (expanded)
206
+ verbatim('Knowledge', vm.sections.find(s => s.title === 'Knowledge')?.items ?? []);
207
+ }
208
+ else {
209
+ if (action === 'memory-sync') {
210
+ section('CURATE MEMORY');
211
+ const state = full ? title.replace(/^Curate Memory · /, '') : v?.state ?? title;
212
+ if (state !== 'Curate Memory')
213
+ line(state);
214
+ }
215
+ else
216
+ section(action === 'session-close' ? 'Session closed' : v?.kind !== 'details' && !full ? v?.state ?? title : title);
217
+ if (action === 'session-close')
218
+ line(v?.state ?? 'Check saved state');
219
+ if (full && v?.reviewRequired)
220
+ line('Review required · not approval.');
221
+ if (!full && v?.kind !== 'details') {
222
+ v?.facts.forEach(x => line(x));
223
+ if (v?.attention.length) {
224
+ line();
225
+ section('ATTENTION');
226
+ v.attention.forEach(x => line(x));
227
+ }
228
+ }
229
+ else {
230
+ vm.metrics.forEach(m => line(`${m.label} ${m.value}${m.detail ? ' · ' + m.detail : ''}`));
231
+ if (!vm.sections.some(s => s.title === 'Knowledge detail'))
232
+ vm.notices.forEach(x => line(x));
233
+ for (const s of vm.sections) {
234
+ section(s.title);
235
+ s.items.forEach((i, n) => { if (n)
236
+ inset(); line(i.title); });
237
+ verbatim(s.title, s.items);
238
+ }
239
+ }
240
+ }
241
+ // Exact reviews precede the approval menu; reading and approving remain distinct.
242
+ if (v?.prompt) {
243
+ line();
244
+ wrapText(v.prompt, width - 2).forEach(x => line(x));
245
+ }
246
+ lines.push((plain ? '+' : '╰') + rule.repeat(width - 1));
247
+ const actions = numberedActions(vm, full);
248
+ const menu = [];
249
+ if (actions.length) {
250
+ menu.push('', 'Available actions:', '');
251
+ for (const a of actions) {
252
+ const key = ` ${a.number} > `;
253
+ const parts = wrapText(a.label, width - key.length);
254
+ menu.push(key + parts[0], ...parts.slice(1).map(x => ' '.repeat(key.length) + x));
255
+ if (a.approval)
256
+ menu.push(' Explicit approval required.');
257
+ if (a.input)
258
+ menu.push(...wrapText(a.input.prompt, width - 6).map(x => ' ' + x));
259
+ }
260
+ menu.push('', 'Reply with a number or the command name.');
261
+ }
262
+ // Keep the service separator outside the record and its metadata.
263
+ if (vm.sections.some(s => s.title === 'Knowledge detail'))
264
+ bodies.push('-------------\n' + vm.notices.join('\n'));
265
+ if (diagnostics || action === 'curation' || full && action === 'migration')
266
+ for (const s of vm.diagnostics ?? [])
267
+ verbatim(s.title, s.items);
268
+ const panel = textFence(lines.join('\n'));
269
+ const exact = bodies.map(textFence);
270
+ const approval = full && actions.some(a => a.approval) && (action === 'memory-sync' || action === 'migration')
271
+ ? action === 'memory-sync' ? 'Approve these exact changes?' : `${actions.find(a => a.approval).label}?` : '';
272
+ return [panel, ...exact, menu.length ? textFence(menu.join('\n').replace(/^\n/, '').trimEnd()) : '', approval].filter(Boolean).join('\n\n');
273
+ }
274
+ /** Public sanitized errors have no executable retry/apply action. */
275
+ export function renderTextError(message, plain = false) {
276
+ return renderProductText({ version: 1, title: 'Prodero · Error', metrics: [], notices: [message], sections: [], actions: [], textScene: { action: 'error' } }, false, true, plain);
277
+ }
278
+ //# sourceMappingURL=text-layout.js.map
@@ -0,0 +1,53 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { runNpmUpdate, NpmUpdateError } from './core/npm-update.js';
3
+ const help = `Usage: prodero update [exact-version] [--yes]
4
+
5
+ Finish work and close Codex and Claude before updating. The terminal waits for
6
+ npm and verifies the installed CLI; reopen your applications and reconnect afterward.
7
+ Only an ordinary same-user global npm installation with Node 22.14–22.x/npm 10.9.x
8
+ is supported. Install scripts are disabled; project and host settings are untouched.
9
+
10
+ Without a version, an interactive terminal checks the latest public release.
11
+ Non-interactive use requires an exact stable version and --yes, confirming that
12
+ work has ended and applications are closed. Equal versions are a no-op; downgrades
13
+ are refused. No sudo, automatic application closing or package rollback is used.`;
14
+ /** Closing stdin or Ctrl-C at the maintenance prompt is a refusal. */
15
+ export function terminalConfirmation(question, input = process.stdin, output = process.stdout) {
16
+ const terminal = createInterface({ input, output });
17
+ return new Promise(resolve => { let done = false; const finish = (answer) => { if (done)
18
+ return; done = true; terminal.close(); resolve(answer); }; terminal.once('close', () => finish(false)); terminal.once('SIGINT', () => finish(false)); terminal.question(question).then(answer => finish(/^y(?:es)?$/i.test(answer.trim())), () => finish(false)); });
19
+ }
20
+ export async function updateCommand(args, dependencies = {}) {
21
+ if (args.length === 1 && ['--help', '-h'].includes(args[0])) {
22
+ (dependencies.write ?? console.log)(help);
23
+ return 0;
24
+ }
25
+ let yes = false, targetVersion;
26
+ for (const arg of args) {
27
+ if (arg === '--yes') {
28
+ if (yes)
29
+ throw new NpmUpdateError('NPM_UPDATE_ARGUMENT', 'Specify --yes only once.');
30
+ yes = true;
31
+ }
32
+ else if (arg.startsWith('-') || targetVersion !== undefined)
33
+ throw new NpmUpdateError('NPM_UPDATE_ARGUMENT', 'Use prodero update [exact-version] [--yes].');
34
+ else
35
+ targetVersion = arg;
36
+ }
37
+ const write = dependencies.write ?? console.log;
38
+ const confirm = dependencies.confirm ?? terminalConfirmation;
39
+ try {
40
+ const result = await runNpmUpdate({ targetVersion, yes }, { ...dependencies, write, confirm, interactive: dependencies.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY) });
41
+ write(result.message);
42
+ return result.exitCode;
43
+ }
44
+ catch (error) {
45
+ if (error instanceof NpmUpdateError) {
46
+ write(`${error.code}: ${error.message}`);
47
+ return error.exitCode;
48
+ }
49
+ write('NPM_UPDATE_FAILED: Cannot complete or verify this update. Inspect this npm installation before retrying.');
50
+ return 1;
51
+ }
52
+ }
53
+ //# sourceMappingURL=update-command.js.map
@@ -0,0 +1,4 @@
1
+ /** Shared copy only: safe to bundle into the App; no execution or host access. */
2
+ export const MANUAL_UPDATE_COMMAND = 'prodero update';
3
+ export const UPDATE_INSTRUCTIONS = 'Finish the current work and close your MCP hosts. In a terminal, run prodero update and review its plan before approving installation. After the terminal reports completion, restart and reconnect your hosts. Open Prodero again and review any project knowledge migration separately. This chat action only shows instructions; it has not installed or staged a runtime, refreshed project integration, or changed your development runtime selection.';
4
+ //# sourceMappingURL=update-instructions.js.map