amicus 1.0.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/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +477 -0
- package/bin/amicus.js +382 -0
- package/electron/assets/icon.png +0 -0
- package/electron/assets/icon.svg +5 -0
- package/electron/fold.js +163 -0
- package/electron/ipc-setup.js +176 -0
- package/electron/load-failsafe.js +85 -0
- package/electron/main.js +468 -0
- package/electron/preload-setup.js +38 -0
- package/electron/preload.js +33 -0
- package/electron/setup-ui-alias-script.js +218 -0
- package/electron/setup-ui-aliases.js +85 -0
- package/electron/setup-ui-keys-script.js +115 -0
- package/electron/setup-ui-keys.js +97 -0
- package/electron/setup-ui-model.js +138 -0
- package/electron/setup-ui-styles.js +327 -0
- package/electron/setup-ui.js +465 -0
- package/electron/summary.js +118 -0
- package/electron/toolbar.js +229 -0
- package/electron/window-position.js +35 -0
- package/package.json +98 -0
- package/scripts/postinstall.js +193 -0
- package/scripts/setup-hooks.js +42 -0
- package/skill/SKILL.md +976 -0
- package/skills/second-opinion/COUNCIL-DESIGN.md +227 -0
- package/skills/second-opinion/MODEL-NOTES.md +104 -0
- package/skills/second-opinion/SKILL.md +389 -0
- package/src/cli-handlers.js +188 -0
- package/src/cli.js +400 -0
- package/src/conflict.js +144 -0
- package/src/context-compression.js +102 -0
- package/src/context.js +199 -0
- package/src/drift.js +144 -0
- package/src/environment.js +157 -0
- package/src/headless.js +742 -0
- package/src/index.js +106 -0
- package/src/jsonl-parser.js +180 -0
- package/src/mcp-server.js +625 -0
- package/src/mcp-tools.js +407 -0
- package/src/opencode-client.js +615 -0
- package/src/prompt-builder.js +355 -0
- package/src/prompts/cowork-agent-prompt.js +118 -0
- package/src/session-manager.js +414 -0
- package/src/session.js +180 -0
- package/src/sidecar/context-builder.js +297 -0
- package/src/sidecar/continue.js +212 -0
- package/src/sidecar/crash-handler.js +56 -0
- package/src/sidecar/fanout-leg.js +107 -0
- package/src/sidecar/fanout-output.js +46 -0
- package/src/sidecar/fanout.js +236 -0
- package/src/sidecar/interactive.js +217 -0
- package/src/sidecar/models.js +135 -0
- package/src/sidecar/progress.js +218 -0
- package/src/sidecar/read.js +183 -0
- package/src/sidecar/resume.js +221 -0
- package/src/sidecar/session-utils.js +288 -0
- package/src/sidecar/setup-window.js +79 -0
- package/src/sidecar/setup.js +280 -0
- package/src/sidecar/start.js +251 -0
- package/src/utils/agent-mapping.js +138 -0
- package/src/utils/alias-audit.js +98 -0
- package/src/utils/alias-resolver.js +77 -0
- package/src/utils/api-key-store.js +259 -0
- package/src/utils/api-key-validation.js +97 -0
- package/src/utils/auth-json.js +109 -0
- package/src/utils/config.js +291 -0
- package/src/utils/curated-models.js +82 -0
- package/src/utils/env-compat.js +38 -0
- package/src/utils/env-loader.js +54 -0
- package/src/utils/idle-watchdog.js +225 -0
- package/src/utils/input-validators.js +127 -0
- package/src/utils/lifecycle.js +43 -0
- package/src/utils/logger.js +84 -0
- package/src/utils/mcp-discovery.js +194 -0
- package/src/utils/mcp-validators.js +78 -0
- package/src/utils/model-catalog.js +103 -0
- package/src/utils/model-fetcher.js +179 -0
- package/src/utils/model-validator.js +207 -0
- package/src/utils/path-setup.js +41 -0
- package/src/utils/port-pid.js +39 -0
- package/src/utils/prompt-source.js +53 -0
- package/src/utils/result-schema.js +261 -0
- package/src/utils/server-setup.js +93 -0
- package/src/utils/session-abort.js +53 -0
- package/src/utils/session-lock.js +95 -0
- package/src/utils/shared-server.js +216 -0
- package/src/utils/start-helpers.js +76 -0
- package/src/utils/thinking-validators.js +92 -0
- package/src/utils/update-notifier-loader.js +18 -0
- package/src/utils/updater.js +157 -0
- package/src/utils/validators.js +300 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Amicus - Main Module
|
|
3
|
+
*
|
|
4
|
+
* Spec Reference: §9 Implementation
|
|
5
|
+
* Re-exports all public APIs for the sidecar CLI.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Import sidecar operations from modular components
|
|
9
|
+
const { startSidecar, generateTaskId, runInteractive, HEARTBEAT_INTERVAL } = require('./sidecar/start');
|
|
10
|
+
const { resumeSidecar } = require('./sidecar/resume');
|
|
11
|
+
const { continueSidecar } = require('./sidecar/continue');
|
|
12
|
+
const { readSidecar, listSidecars, formatAge } = require('./sidecar/read');
|
|
13
|
+
const { buildContext, parseDuration } = require('./sidecar/context-builder');
|
|
14
|
+
const { runFanout } = require('./sidecar/fanout');
|
|
15
|
+
|
|
16
|
+
// Import from prompt-builder
|
|
17
|
+
const { buildSystemPrompt, buildPrompts, getSummaryTemplate, SUMMARY_TEMPLATE } = require('./prompt-builder');
|
|
18
|
+
|
|
19
|
+
// Import from headless
|
|
20
|
+
const { runHeadless, extractSummary, formatFoldOutput, DEFAULT_TIMEOUT, FOLD_MARKER, COMPLETE_MARKER } = require('./headless');
|
|
21
|
+
|
|
22
|
+
// Track B modules - Context, Session Management, Conflict & Drift Detection
|
|
23
|
+
const { filterContext, estimateTokens, takeLastNTurns } = require('./context');
|
|
24
|
+
const { createSession, updateSession, getSession, saveConversation, saveSummary, getSessionDir, SESSION_STATUS } = require('./session-manager');
|
|
25
|
+
const { detectConflicts, formatConflictWarning } = require('./conflict');
|
|
26
|
+
const { calculateDrift, formatDriftWarning, countTurnsSince, isDriftSignificant } = require('./drift');
|
|
27
|
+
|
|
28
|
+
// v3 modules - Environment detection & Context compression
|
|
29
|
+
const { detectEnvironment, inferClient, getSessionRoot } = require('./environment');
|
|
30
|
+
const { compressContext, estimateTokenCount, buildPreamble } = require('./context-compression');
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
// Canonical Amicus public API (the *Sidecar names below are deprecated shims)
|
|
34
|
+
startAmicus: startSidecar,
|
|
35
|
+
listAmicus: listSidecars,
|
|
36
|
+
resumeAmicus: resumeSidecar,
|
|
37
|
+
continueAmicus: continueSidecar,
|
|
38
|
+
readAmicus: readSidecar,
|
|
39
|
+
runFanout,
|
|
40
|
+
|
|
41
|
+
// DEPRECATED(amicus-shim): remove *Sidecar exports in a future revision — see docs/SHIMS.md
|
|
42
|
+
// Primary sidecar APIs
|
|
43
|
+
startSidecar,
|
|
44
|
+
listSidecars,
|
|
45
|
+
resumeSidecar,
|
|
46
|
+
continueSidecar,
|
|
47
|
+
readSidecar,
|
|
48
|
+
generateTaskId,
|
|
49
|
+
|
|
50
|
+
// Context building
|
|
51
|
+
buildContext,
|
|
52
|
+
parseDuration,
|
|
53
|
+
formatAge,
|
|
54
|
+
|
|
55
|
+
// Re-export from prompt-builder
|
|
56
|
+
buildSystemPrompt,
|
|
57
|
+
buildPrompts,
|
|
58
|
+
getSummaryTemplate,
|
|
59
|
+
SUMMARY_TEMPLATE,
|
|
60
|
+
|
|
61
|
+
// Re-export from headless
|
|
62
|
+
runHeadless,
|
|
63
|
+
extractSummary,
|
|
64
|
+
formatFoldOutput,
|
|
65
|
+
DEFAULT_TIMEOUT,
|
|
66
|
+
FOLD_MARKER,
|
|
67
|
+
COMPLETE_MARKER,
|
|
68
|
+
|
|
69
|
+
// Re-export from context (Track B)
|
|
70
|
+
filterContext,
|
|
71
|
+
estimateTokens,
|
|
72
|
+
takeLastNTurns,
|
|
73
|
+
|
|
74
|
+
// Re-export from session-manager (Track B)
|
|
75
|
+
createSession,
|
|
76
|
+
updateSession,
|
|
77
|
+
getSession,
|
|
78
|
+
saveConversation,
|
|
79
|
+
saveSummary,
|
|
80
|
+
getSessionDir,
|
|
81
|
+
SESSION_STATUS,
|
|
82
|
+
|
|
83
|
+
// Re-export from conflict (Track B)
|
|
84
|
+
detectConflicts,
|
|
85
|
+
formatConflictWarning,
|
|
86
|
+
|
|
87
|
+
// Re-export from drift (Track B)
|
|
88
|
+
calculateDrift,
|
|
89
|
+
formatDriftWarning,
|
|
90
|
+
countTurnsSince,
|
|
91
|
+
isDriftSignificant,
|
|
92
|
+
|
|
93
|
+
// Re-export from environment (v3)
|
|
94
|
+
detectEnvironment,
|
|
95
|
+
inferClient,
|
|
96
|
+
getSessionRoot,
|
|
97
|
+
|
|
98
|
+
// Re-export from context-compression (v3)
|
|
99
|
+
compressContext,
|
|
100
|
+
estimateTokenCount,
|
|
101
|
+
buildPreamble,
|
|
102
|
+
|
|
103
|
+
// Internal exports (for use by sidecar modules)
|
|
104
|
+
runInteractive,
|
|
105
|
+
HEARTBEAT_INTERVAL
|
|
106
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL Parser
|
|
3
|
+
*
|
|
4
|
+
* Spec Reference: §5.3 Context Filtering Algorithm, §5.3 Context Format
|
|
5
|
+
* Parses Claude Code conversation JSONL files and formats them for context passing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse a single line of JSONL content
|
|
12
|
+
* @param {string} line - A single line from a JSONL file
|
|
13
|
+
* @returns {object|null} Parsed JSON object or null if invalid
|
|
14
|
+
*/
|
|
15
|
+
function parseJSONLLine(line) {
|
|
16
|
+
if (!line || !line.trim()) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(line);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Read and parse a JSONL file
|
|
29
|
+
* @param {string} filePath - Path to the JSONL file
|
|
30
|
+
* @returns {object[]} Array of parsed message objects
|
|
31
|
+
* @throws {Error} If file cannot be read
|
|
32
|
+
*/
|
|
33
|
+
function readJSONL(filePath) {
|
|
34
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
35
|
+
|
|
36
|
+
return content
|
|
37
|
+
.split('\n')
|
|
38
|
+
.map(line => parseJSONLLine(line))
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Extract timestamp from a message object
|
|
44
|
+
* @param {object} message - Message object with optional timestamp field
|
|
45
|
+
* @returns {Date|null} Date object or null if invalid/missing
|
|
46
|
+
*/
|
|
47
|
+
function extractTimestamp(message) {
|
|
48
|
+
if (!message || !message.timestamp) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const date = new Date(message.timestamp);
|
|
53
|
+
|
|
54
|
+
// Check if date is valid (invalid dates return NaN for getTime())
|
|
55
|
+
if (isNaN(date.getTime())) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return date;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Format a timestamp for display (e.g., "10:30" or "10:30 AM")
|
|
64
|
+
* @param {string} timestamp - ISO timestamp string
|
|
65
|
+
* @returns {string} Formatted time string
|
|
66
|
+
*/
|
|
67
|
+
function formatTime(timestamp) {
|
|
68
|
+
const date = new Date(timestamp);
|
|
69
|
+
return date.toLocaleTimeString('en-US', {
|
|
70
|
+
hour: '2-digit',
|
|
71
|
+
minute: '2-digit'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extract text content from a message
|
|
77
|
+
* Handles both string content and array content (Claude API format)
|
|
78
|
+
* @param {object} message - Message object with content field
|
|
79
|
+
* @returns {string} Extracted text content
|
|
80
|
+
*/
|
|
81
|
+
function extractContent(message) {
|
|
82
|
+
if (!message || !message.message) {
|
|
83
|
+
return '';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const content = message.message.content;
|
|
87
|
+
|
|
88
|
+
if (!content) {
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// String content (simple format)
|
|
93
|
+
if (typeof content === 'string') {
|
|
94
|
+
return content;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Array content (Claude API format with text blocks)
|
|
98
|
+
if (Array.isArray(content)) {
|
|
99
|
+
return content
|
|
100
|
+
.map(block => block.text || '')
|
|
101
|
+
.join('');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Format a single message for context output
|
|
109
|
+
* Spec Reference: §5.3 Context Format
|
|
110
|
+
*
|
|
111
|
+
* @param {object} message - Parsed message object
|
|
112
|
+
* @returns {string} Formatted message string
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // User message
|
|
116
|
+
* formatMessage({ type: 'user', message: { content: 'Hello' }, timestamp: '2025-01-25T10:30:00Z' })
|
|
117
|
+
* // Returns: "[User @ 10:30 AM] Hello"
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* // Tool use message
|
|
121
|
+
* formatMessage({ type: 'tool_use', tool: 'Read', input: { path: 'file.ts' }, timestamp: '...' })
|
|
122
|
+
* // Returns: "[Tool: Read file.ts]"
|
|
123
|
+
*/
|
|
124
|
+
function formatMessage(message) {
|
|
125
|
+
if (!message || !message.type) {
|
|
126
|
+
return '';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const time = message.timestamp ? formatTime(message.timestamp) : '';
|
|
130
|
+
|
|
131
|
+
switch (message.type) {
|
|
132
|
+
case 'user': {
|
|
133
|
+
const content = extractContent(message);
|
|
134
|
+
return `[User @ ${time}] ${content}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
case 'assistant': {
|
|
138
|
+
const content = extractContent(message);
|
|
139
|
+
return `[Assistant @ ${time}] ${content}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case 'tool_use': {
|
|
143
|
+
const toolName = message.tool || 'Unknown';
|
|
144
|
+
const path = message.input?.path || '';
|
|
145
|
+
return path ? `[Tool: ${toolName} ${path}]` : `[Tool: ${toolName}]`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
default:
|
|
149
|
+
return '';
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Format an array of messages into a context string
|
|
155
|
+
* Spec Reference: §5.3 Context Format
|
|
156
|
+
*
|
|
157
|
+
* @param {object[]} messages - Array of parsed message objects
|
|
158
|
+
* @returns {string} Formatted context string with messages separated by double newlines
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* // Format: [User @ 10:30] message\n\n[Assistant @ 10:31] response\n\n[Tool: Read path/file]
|
|
162
|
+
*/
|
|
163
|
+
function formatContext(messages) {
|
|
164
|
+
if (!messages || messages.length === 0) {
|
|
165
|
+
return '';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return messages
|
|
169
|
+
.map(msg => formatMessage(msg))
|
|
170
|
+
.filter(Boolean)
|
|
171
|
+
.join('\n\n');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
module.exports = {
|
|
175
|
+
parseJSONLLine,
|
|
176
|
+
readJSONL,
|
|
177
|
+
extractTimestamp,
|
|
178
|
+
formatMessage,
|
|
179
|
+
formatContext
|
|
180
|
+
};
|