ticlawk 0.1.16-dev.1 → 0.1.16-dev.11
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/README.md +13 -0
- package/bin/ticlawk.mjs +116 -0
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +226 -28
- package/src/adapters/ticlawk/index.mjs +258 -113
- package/src/cli/agent-commands.mjs +594 -8
- package/src/core/agent-cli-handlers.mjs +443 -3
- package/src/core/agent-home.mjs +85 -0
- package/src/core/argv.mjs +11 -1
- package/src/core/http.mjs +121 -0
- package/src/core/reminder-ticker.mjs +70 -0
- package/src/core/runtime-contract.mjs +1 -1
- package/src/core/runtime-support.mjs +31 -59
- package/src/core/ticlawk-control.mjs +3 -3
- package/src/migrate/write-initial-memory.mjs +101 -0
- package/src/runtimes/_shared/standing-prompt.mjs +296 -77
- package/src/runtimes/claude-code/index.mjs +28 -131
- package/src/runtimes/codex/index.mjs +15 -39
- package/src/runtimes/openclaw/index.mjs +39 -30
- package/src/runtimes/openclaw/target.mjs +0 -30
- package/src/runtimes/opencode/index.mjs +19 -54
- package/src/runtimes/pi/index.mjs +16 -49
- package/ticlawk.mjs +31 -6
- package/src/adapters/ticlawk/cards.mjs +0 -149
- package/src/core/media/outbound.mjs +0 -163
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { extname } from 'node:path';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
-
|
|
5
|
-
export const MIME_MAP = {
|
|
6
|
-
'.png': 'image/png',
|
|
7
|
-
'.jpg': 'image/jpeg',
|
|
8
|
-
'.jpeg': 'image/jpeg',
|
|
9
|
-
'.gif': 'image/gif',
|
|
10
|
-
'.webp': 'image/webp',
|
|
11
|
-
'.svg': 'image/svg+xml',
|
|
12
|
-
'.mp4': 'video/mp4',
|
|
13
|
-
'.webm': 'video/webm',
|
|
14
|
-
'.pdf': 'application/pdf',
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
function mediaExtensionPattern() {
|
|
18
|
-
return Object.keys(MIME_MAP).map((entry) => entry.replace('.', '\\.')).join('|');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function stripUrlSuffix(value) {
|
|
22
|
-
return String(value || '').replace(/[?#].*$/, '');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function trimCandidate(value) {
|
|
26
|
-
return String(value || '')
|
|
27
|
-
.trim()
|
|
28
|
-
.replace(/^<|>$/g, '')
|
|
29
|
-
.replace(/^["']|["']$/g, '')
|
|
30
|
-
.replace(/\\\//g, '/');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function hasKnownMediaExtension(value) {
|
|
34
|
-
return Boolean(MIME_MAP[extname(stripUrlSuffix(value)).toLowerCase()]);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function normalizeMediaPath(value) {
|
|
38
|
-
let candidate = trimCandidate(value);
|
|
39
|
-
if (!candidate) return null;
|
|
40
|
-
|
|
41
|
-
candidate = candidate.replace(/^about:/i, '');
|
|
42
|
-
|
|
43
|
-
if (/^file:/i.test(candidate)) {
|
|
44
|
-
try {
|
|
45
|
-
candidate = fileURLToPath(candidate);
|
|
46
|
-
} catch {
|
|
47
|
-
candidate = candidate.replace(/^file:(?:\/\/)?/i, '');
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
candidate = stripUrlSuffix(candidate);
|
|
52
|
-
|
|
53
|
-
if (candidate.startsWith('~')) {
|
|
54
|
-
candidate = candidate.replace(/^~/, homedir());
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (candidate.startsWith('/')) {
|
|
58
|
-
candidate = candidate.replace(/^\/{2,}/, '/');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!candidate.startsWith('/')) return null;
|
|
62
|
-
if (!hasKnownMediaExtension(candidate)) return null;
|
|
63
|
-
return candidate;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function addMediaCandidate(paths, value) {
|
|
67
|
-
const normalized = normalizeMediaPath(value);
|
|
68
|
-
if (normalized) paths.add(normalized);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function extractMediaPaths(text) {
|
|
72
|
-
const extPattern = mediaExtensionPattern();
|
|
73
|
-
const paths = new Set();
|
|
74
|
-
const candidates = [];
|
|
75
|
-
|
|
76
|
-
const body = String(text || '');
|
|
77
|
-
for (const match of body.matchAll(/<img[^>]+src=["']([^"']+)["'][^>]*>/gi)) {
|
|
78
|
-
candidates.push({ index: match.index || 0, value: match[1] });
|
|
79
|
-
}
|
|
80
|
-
for (const match of body.matchAll(/!?\[[^\]]*\]\(\s*<([^>\n]+)>/gi)) {
|
|
81
|
-
candidates.push({ index: match.index || 0, value: match[1] });
|
|
82
|
-
}
|
|
83
|
-
for (const match of body.matchAll(/!?\[[^\]]*\]\(\s*([^\s)>]+)>?/gi)) {
|
|
84
|
-
candidates.push({ index: match.index || 0, value: match[1] });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const re = new RegExp(`((?:file:(?://)?|about:(?://)?)?(?:~|/{1,3})[^\\s"'<>)]*?(?:${extPattern})(?:[?#][^\\s"'<>)]*)?)`, 'gi');
|
|
88
|
-
for (const match of body.matchAll(re)) {
|
|
89
|
-
candidates.push({ index: match.index || 0, value: match[1] });
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
candidates
|
|
93
|
-
.sort((a, b) => a.index - b.index)
|
|
94
|
-
.forEach((candidate) => addMediaCandidate(paths, candidate.value));
|
|
95
|
-
|
|
96
|
-
return [...paths];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function escapeRegExp(value) {
|
|
100
|
-
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function referencesPath(value, normalizedPaths) {
|
|
104
|
-
const normalized = normalizeMediaPath(value);
|
|
105
|
-
return Boolean(normalized && normalizedPaths.has(normalized));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function pathReferenceVariants(path) {
|
|
109
|
-
const normalized = normalizeMediaPath(path) || path;
|
|
110
|
-
const variants = new Set([normalized]);
|
|
111
|
-
if (normalized.startsWith('/')) {
|
|
112
|
-
variants.add(pathToFileURL(normalized).href);
|
|
113
|
-
variants.add(`about:${normalized}`);
|
|
114
|
-
variants.add(`about://${normalized}`);
|
|
115
|
-
}
|
|
116
|
-
return [...variants].sort((a, b) => b.length - a.length);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function stripMediaPathReferences(text, explicitPaths = []) {
|
|
120
|
-
let next = String(text || '');
|
|
121
|
-
const paths = [...new Set([
|
|
122
|
-
...explicitPaths,
|
|
123
|
-
...extractMediaPaths(next),
|
|
124
|
-
].map((path) => normalizeMediaPath(path)).filter(Boolean))];
|
|
125
|
-
const normalizedPaths = new Set(paths);
|
|
126
|
-
|
|
127
|
-
next = next
|
|
128
|
-
.replace(/<img[^>]+src=["']([^"']+)["'][^>]*>/gi, (match, src) => (
|
|
129
|
-
referencesPath(src, normalizedPaths) ? '' : match
|
|
130
|
-
))
|
|
131
|
-
.replace(/!\[[^\]]*\]\(\s*<([^>\n]+)>(?:\s+["'][^"']*["'])?\s*\)/gi, (match, target) => (
|
|
132
|
-
referencesPath(target, normalizedPaths) ? '' : match
|
|
133
|
-
))
|
|
134
|
-
.replace(/!\[[^\]]*\]\(\s*([^\s)>]+)>?(?:\s+["'][^"']*["'])?\s*\)/gi, (match, target) => (
|
|
135
|
-
referencesPath(target, normalizedPaths) ? '' : match
|
|
136
|
-
));
|
|
137
|
-
|
|
138
|
-
for (const path of paths) {
|
|
139
|
-
for (const variant of pathReferenceVariants(path)) {
|
|
140
|
-
const escapedPath = escapeRegExp(variant);
|
|
141
|
-
next = next
|
|
142
|
-
.replace(new RegExp(`\\[media attached[^\\]]*${escapedPath}[^\\]]*\\]\\s*`, 'gi'), '')
|
|
143
|
-
.replace(new RegExp(`^\\s*${escapedPath}\\s*$`, 'gim'), '')
|
|
144
|
-
.replace(new RegExp(escapedPath, 'g'), '');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return next
|
|
149
|
-
.replace(/<img[^>]+src=["'](?:file:|about:)(?:\/){0,3}(?:tmp|private|var|Users|home)[^"']*["'][^>]*>/gi, '')
|
|
150
|
-
.replace(/!\[[^\]]*\]\(\s*<?(?:file:|about:)(?:\/){0,3}(?:tmp|private|var|Users|home)[^)]*\)/gi, '')
|
|
151
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
152
|
-
.trim();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function normalizeOutboundMedia(result) {
|
|
156
|
-
const explicit = Array.isArray(result?.mediaUrls) ? result.mediaUrls : [];
|
|
157
|
-
const inferred = extractMediaPaths(result?.text || '');
|
|
158
|
-
return [...new Set([...explicit, ...inferred])].map((path) => ({
|
|
159
|
-
kind: 'local_path',
|
|
160
|
-
value: path,
|
|
161
|
-
mime: MIME_MAP[extname(path).toLowerCase()] || 'application/octet-stream',
|
|
162
|
-
}));
|
|
163
|
-
}
|