@aiyiran/myclaw 1.0.196 → 1.0.197

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.
@@ -0,0 +1,263 @@
1
+ /**
2
+ * ============================================================================
3
+ * MyClaw Artifacts — 学生作品展示面板
4
+ * ============================================================================
5
+ *
6
+ * 功能:
7
+ * 右下角 "🎨 作品" 按钮,点击弹出作品面板
8
+ * 从 workspace 的 .myclaw/__MY_ARTIFACTS__.json 读取作品清单
9
+ *
10
+ * JSON 数据格式:
11
+ * {
12
+ * "workspace_id": "main",
13
+ * "assets": [
14
+ * { "name": "射击游戏", "type": "html", "path": "myclaw/shooting-game.html" }
15
+ * ]
16
+ * }
17
+ *
18
+ * URL 拼接规则:
19
+ * {origin}/cmd/api/preview?path={wsPrefix}/{asset.path}
20
+ * main → workspace, 其他 → workspace-{name}
21
+ * ============================================================================
22
+ */
23
+ (function () {
24
+ 'use strict';
25
+
26
+ // ═══ 状态 ═══
27
+ var artifactsOpen = false;
28
+
29
+ // ═══ 工具:从 URL 解析 agent 名称 ═══
30
+ function getAgentName() {
31
+ var params = new URLSearchParams(window.location.search);
32
+ // 优先从 session 参数解析: agent:main:feishu:... → main
33
+ var session = params.get('session');
34
+ if (session) {
35
+ var decoded = decodeURIComponent(session);
36
+ if (decoded.indexOf('agent:') === 0) {
37
+ var parts = decoded.split(':');
38
+ if (parts.length >= 2) return parts[1];
39
+ }
40
+ }
41
+ // fallback: agent 参数
42
+ var agent = params.get('agent');
43
+ if (agent) return agent;
44
+ return '';
45
+ }
46
+
47
+ // ═══ 创建按钮 ═══
48
+ function createArtifactsButton() {
49
+ if (document.querySelector('#myclaw-artifacts-btn')) return;
50
+
51
+ var btn = document.createElement('div');
52
+ btn.id = 'myclaw-artifacts-btn';
53
+ btn.style.cssText = [
54
+ 'position: fixed',
55
+ 'bottom: 8px',
56
+ 'right: 140px',
57
+ 'padding: 3px 10px',
58
+ 'background: rgba(100, 100, 100, 0.7)',
59
+ 'color: #fff',
60
+ 'font-size: 11px',
61
+ 'font-weight: bold',
62
+ 'font-family: monospace',
63
+ 'border-radius: 4px',
64
+ 'z-index: 99999',
65
+ 'user-select: none',
66
+ 'cursor: pointer',
67
+ 'transition: all 0.2s',
68
+ 'letter-spacing: 0.5px',
69
+ ].join(';');
70
+ btn.textContent = '\uD83C\uDFA8 \u4F5C\u54C1';
71
+ btn.title = '\u67E5\u770B\u5B66\u751F\u4F5C\u54C1';
72
+
73
+ btn.onmouseenter = function () { btn.style.background = 'rgba(80, 80, 80, 0.95)'; btn.style.transform = 'scale(1.05)'; };
74
+ btn.onmouseleave = function () { if (!artifactsOpen) { btn.style.background = 'rgba(100, 100, 100, 0.7)'; } btn.style.transform = 'scale(1)'; };
75
+ btn.onclick = function (e) {
76
+ e.stopPropagation();
77
+ if (artifactsOpen) {
78
+ closeArtifactsPanel();
79
+ } else {
80
+ openArtifactsPanel();
81
+ }
82
+ };
83
+
84
+ document.body.appendChild(btn);
85
+ }
86
+
87
+ // ═══ 打开面板 ═══
88
+ function openArtifactsPanel() {
89
+ if (document.querySelector('#myclaw-artifacts-modal')) return;
90
+ artifactsOpen = true;
91
+
92
+ // 按钮 active 态
93
+ var btn = document.querySelector('#myclaw-artifacts-btn');
94
+ if (btn) btn.style.background = 'rgba(80, 80, 80, 0.95)';
95
+
96
+ // 遮罩
97
+ var overlay = document.createElement('div');
98
+ overlay.id = 'myclaw-artifacts-modal';
99
+ overlay.style.cssText = [
100
+ 'position: fixed',
101
+ 'top: 0',
102
+ 'left: 0',
103
+ 'width: 100vw',
104
+ 'height: 100vh',
105
+ 'background: rgba(0, 0, 0, 0.3)',
106
+ 'z-index: 99998',
107
+ 'display: flex',
108
+ 'align-items: center',
109
+ 'justify-content: center',
110
+ 'animation: myclaw-fade-in 0.15s ease',
111
+ ].join(';');
112
+
113
+ // 面板容器
114
+ var box = document.createElement('div');
115
+ box.style.cssText = [
116
+ 'width: 480px',
117
+ 'max-height: 70vh',
118
+ 'background: #1e1e2e',
119
+ 'border-radius: 8px',
120
+ 'overflow: hidden',
121
+ 'display: flex',
122
+ 'flex-direction: column',
123
+ 'box-shadow: 0 8px 32px rgba(0,0,0,0.4)',
124
+ ].join(';');
125
+
126
+ // 标题栏
127
+ var header = document.createElement('div');
128
+ header.style.cssText = [
129
+ 'display: flex',
130
+ 'align-items: center',
131
+ 'justify-content: space-between',
132
+ 'padding: 10px 16px',
133
+ 'background: #2d2d3f',
134
+ 'color: #cdd6f4',
135
+ 'font-size: 14px',
136
+ 'font-family: monospace',
137
+ 'user-select: none',
138
+ ].join(';');
139
+ header.innerHTML = '<span>\uD83C\uDFA8 \u5B66\u751F\u4F5C\u54C1</span>';
140
+
141
+ var closeBtn = document.createElement('span');
142
+ closeBtn.textContent = '\u2715';
143
+ closeBtn.style.cssText = 'cursor:pointer;padding:2px 6px;border-radius:3px;font-size:14px;transition:background 0.15s;';
144
+ closeBtn.onmouseenter = function () { closeBtn.style.background = 'rgba(255,255,255,0.1)'; };
145
+ closeBtn.onmouseleave = function () { closeBtn.style.background = 'none'; };
146
+ closeBtn.onclick = function () { closeArtifactsPanel(); };
147
+ header.appendChild(closeBtn);
148
+
149
+ // 内容区
150
+ var content = document.createElement('div');
151
+ content.id = 'myclaw-artifacts-content';
152
+ content.style.cssText = [
153
+ 'flex: 1',
154
+ 'overflow-y: auto',
155
+ 'padding: 16px',
156
+ 'color: #cdd6f4',
157
+ 'font-family: monospace',
158
+ 'font-size: 13px',
159
+ ].join(';');
160
+
161
+ // 加载中
162
+ content.innerHTML = '<div style="text-align:center;padding:32px;color:#888;">加载中...</div>';
163
+
164
+ box.appendChild(header);
165
+ box.appendChild(content);
166
+ overlay.appendChild(box);
167
+
168
+ // 点击遮罩关闭
169
+ overlay.onclick = function (e) {
170
+ if (e.target === overlay) closeArtifactsPanel();
171
+ };
172
+
173
+ document.body.appendChild(overlay);
174
+
175
+ // 异步请求数据
176
+ fetchArtifacts(content);
177
+ }
178
+
179
+ // ═══ 请求数据 ═══
180
+ function fetchArtifacts(contentEl) {
181
+ var url = window.location.origin + '/cmd/api/preview?path=.myclaw/__MY_ARTIFACTS__.json';
182
+ fetch(url)
183
+ .then(function (res) {
184
+ if (!res.ok) throw new Error('HTTP ' + res.status);
185
+ return res.json();
186
+ })
187
+ .then(function (data) {
188
+ if (!data || !data.assets || !data.assets.length) {
189
+ contentEl.innerHTML = '<div style="text-align:center;padding:32px;color:#888;">暂无作品</div>';
190
+ return;
191
+ }
192
+ renderArtifactsList(contentEl, data);
193
+ })
194
+ .catch(function (err) {
195
+ console.error('[myclaw-artifacts] 加载失败:', err);
196
+ contentEl.innerHTML = '<div style="text-align:center;padding:32px;color:#ff6b6b;">加载失败,请稍后重试</div>';
197
+ });
198
+ }
199
+
200
+ // ═══ 渲染列表 ═══
201
+ function renderArtifactsList(container, data) {
202
+ container.innerHTML = '';
203
+ // 拼接: base + workspace前缀 + / + 资源路径
204
+ // main → workspace, 其他 → workspace-{name}
205
+ var wsName = data.workspace_id || '';
206
+ var wsPrefix = wsName === 'main' ? 'workspace' : 'workspace-' + wsName;
207
+ var baseUrl = window.location.origin + '/cmd/api/preview?path=' + wsPrefix + '/';
208
+
209
+ data.assets.forEach(function (asset) {
210
+ var card = document.createElement('a');
211
+ card.href = baseUrl + asset.path;
212
+ card.target = '_blank';
213
+ card.rel = 'noopener noreferrer';
214
+ card.style.cssText = [
215
+ 'display: block',
216
+ 'padding: 12px 14px',
217
+ 'margin-bottom: 10px',
218
+ 'background: #2d2d3f',
219
+ 'border-radius: 6px',
220
+ 'color: #cdd6f4',
221
+ 'text-decoration: none',
222
+ 'transition: background 0.15s',
223
+ 'cursor: pointer',
224
+ ].join(';');
225
+ card.onmouseenter = function () { card.style.background = '#3d3d5c'; };
226
+ card.onmouseleave = function () { card.style.background = '#2d2d3f'; };
227
+
228
+ var title = document.createElement('div');
229
+ title.style.cssText = 'font-size: 14px; font-weight: bold; margin-bottom: 4px;';
230
+ title.textContent = asset.name || '未命名作品';
231
+
232
+ var meta = document.createElement('div');
233
+ meta.style.cssText = 'font-size: 11px; color: #888;';
234
+ meta.textContent = asset.type ? asset.type.toUpperCase() : '';
235
+
236
+ card.appendChild(title);
237
+ card.appendChild(meta);
238
+ container.appendChild(card);
239
+ });
240
+ }
241
+
242
+ // ═══ 关闭面板 ═══
243
+ function closeArtifactsPanel() {
244
+ var modal = document.querySelector('#myclaw-artifacts-modal');
245
+ if (modal) modal.remove();
246
+ artifactsOpen = false;
247
+
248
+ var btn = document.querySelector('#myclaw-artifacts-btn');
249
+ if (btn) btn.style.background = 'rgba(100, 100, 100, 0.7)';
250
+ }
251
+
252
+ // ═══ 启动 ═══
253
+ function init() {
254
+ createArtifactsButton();
255
+ console.log('[myclaw-artifacts] ✅ 初始化完成');
256
+ }
257
+
258
+ if (document.readyState === 'loading') {
259
+ document.addEventListener('DOMContentLoaded', init);
260
+ } else {
261
+ init();
262
+ }
263
+ })();
@@ -96,7 +96,6 @@
96
96
 
97
97
  // ═══ 1.2 右下角 CMD 按钮(弹框 iframe) ═══
98
98
  var cmdOpen = false;
99
- var artifactsOpen = false;
100
99
 
101
100
  function createCmdButton() {
102
101
  if (document.querySelector("#myclaw-cmd-btn")) return;
@@ -229,225 +228,6 @@
229
228
  if (btn) btn.style.background = "rgba(59, 130, 246, 0.85)";
230
229
  }
231
230
 
232
- // ═══ 1.3 学生作品展示 ═══
233
-
234
- function getAgentName() {
235
- var params = new URLSearchParams(window.location.search);
236
- // 优先从 session 参数解析: agent:main:feishu:... → main
237
- var session = params.get("session");
238
- if (session) {
239
- var decoded = decodeURIComponent(session);
240
- if (decoded.indexOf("agent:") === 0) {
241
- var parts = decoded.split(":");
242
- if (parts.length >= 2) return parts[1];
243
- }
244
- }
245
- // fallback: agent 参数
246
- var agent = params.get("agent");
247
- if (agent) return agent;
248
- return "";
249
- }
250
-
251
- function createArtifactsButton() {
252
- if (document.querySelector("#myclaw-artifacts-btn")) return;
253
-
254
- var btn = document.createElement("div");
255
- btn.id = "myclaw-artifacts-btn";
256
- btn.style.cssText = [
257
- "position: fixed",
258
- "bottom: 8px",
259
- "right: 140px",
260
- "padding: 3px 10px",
261
- "background: rgba(100, 100, 100, 0.7)",
262
- "color: #fff",
263
- "font-size: 11px",
264
- "font-weight: bold",
265
- "font-family: monospace",
266
- "border-radius: 4px",
267
- "z-index: 99999",
268
- "user-select: none",
269
- "cursor: pointer",
270
- "transition: all 0.2s",
271
- "letter-spacing: 0.5px",
272
- ].join(";");
273
- btn.textContent = "\uD83C\uDFA8 \u4F5C\u54C1";
274
- btn.title = "\u67E5\u770B\u5B66\u751F\u4F5C\u54C1";
275
-
276
- btn.onmouseenter = function () { btn.style.background = "rgba(80, 80, 80, 0.95)"; btn.style.transform = "scale(1.05)"; };
277
- btn.onmouseleave = function () { if (!artifactsOpen) { btn.style.background = "rgba(100, 100, 100, 0.7)"; } btn.style.transform = "scale(1)"; };
278
- btn.onclick = function (e) {
279
- e.stopPropagation();
280
- if (artifactsOpen) {
281
- closeArtifactsPanel();
282
- } else {
283
- openArtifactsPanel();
284
- }
285
- };
286
-
287
- document.body.appendChild(btn);
288
- }
289
-
290
- function openArtifactsPanel() {
291
- if (document.querySelector("#myclaw-artifacts-modal")) return;
292
- artifactsOpen = true;
293
-
294
- // 按钮 active 态
295
- var btn = document.querySelector("#myclaw-artifacts-btn");
296
- if (btn) btn.style.background = "rgba(80, 80, 80, 0.95)";
297
-
298
- // 遮罩
299
- var overlay = document.createElement("div");
300
- overlay.id = "myclaw-artifacts-modal";
301
- overlay.style.cssText = [
302
- "position: fixed",
303
- "top: 0",
304
- "left: 0",
305
- "width: 100vw",
306
- "height: 100vh",
307
- "background: rgba(0, 0, 0, 0.3)",
308
- "z-index: 99998",
309
- "display: flex",
310
- "align-items: center",
311
- "justify-content: center",
312
- "animation: myclaw-fade-in 0.15s ease",
313
- ].join(";");
314
-
315
- // 面板容器
316
- var box = document.createElement("div");
317
- box.style.cssText = [
318
- "width: 480px",
319
- "max-height: 70vh",
320
- "background: #1e1e2e",
321
- "border-radius: 8px",
322
- "overflow: hidden",
323
- "display: flex",
324
- "flex-direction: column",
325
- "box-shadow: 0 8px 32px rgba(0,0,0,0.4)",
326
- ].join(";");
327
-
328
- // 标题栏
329
- var header = document.createElement("div");
330
- header.style.cssText = [
331
- "display: flex",
332
- "align-items: center",
333
- "justify-content: space-between",
334
- "padding: 10px 16px",
335
- "background: #2d2d3f",
336
- "color: #cdd6f4",
337
- "font-size: 14px",
338
- "font-family: monospace",
339
- "user-select: none",
340
- ].join(";");
341
- header.innerHTML = '<span>\uD83C\uDFA8 \u5B66\u751F\u4F5C\u54C1</span>';
342
-
343
- var closeBtn = document.createElement("span");
344
- closeBtn.textContent = "\u2715";
345
- closeBtn.style.cssText = "cursor:pointer;padding:2px 6px;border-radius:3px;font-size:14px;transition:background 0.15s;";
346
- closeBtn.onmouseenter = function () { closeBtn.style.background = "rgba(255,255,255,0.1)"; };
347
- closeBtn.onmouseleave = function () { closeBtn.style.background = "none"; };
348
- closeBtn.onclick = function () { closeArtifactsPanel(); };
349
- header.appendChild(closeBtn);
350
-
351
- // 内容区
352
- var content = document.createElement("div");
353
- content.id = "myclaw-artifacts-content";
354
- content.style.cssText = [
355
- "flex: 1",
356
- "overflow-y: auto",
357
- "padding: 16px",
358
- "color: #cdd6f4",
359
- "font-family: monospace",
360
- "font-size: 13px",
361
- ].join(";");
362
-
363
- // 加载中
364
- content.innerHTML = '<div style="text-align:center;padding:32px;color:#888;">加载中...</div>';
365
-
366
- box.appendChild(header);
367
- box.appendChild(content);
368
- overlay.appendChild(box);
369
-
370
- // 点击遮罩关闭
371
- overlay.onclick = function (e) {
372
- if (e.target === overlay) closeArtifactsPanel();
373
- };
374
-
375
- document.body.appendChild(overlay);
376
-
377
- // 异步请求数据
378
- fetchArtifacts(content);
379
- }
380
-
381
- function fetchArtifacts(contentEl) {
382
- var url = window.location.origin + "/cmd/api/preview?path=.myclaw/__MY_ARTIFACTS__.json";
383
- fetch(url)
384
- .then(function (res) {
385
- if (!res.ok) throw new Error("HTTP " + res.status);
386
- return res.json();
387
- })
388
- .then(function (data) {
389
- if (!data || !data.assets || !data.assets.length) {
390
- contentEl.innerHTML = '<div style="text-align:center;padding:32px;color:#888;">暂无作品</div>';
391
- return;
392
- }
393
- renderArtifactsList(contentEl, data);
394
- })
395
- .catch(function (err) {
396
- console.error("[myclaw-artifacts] 加载失败:", err);
397
- contentEl.innerHTML = '<div style="text-align:center;padding:32px;color:#ff6b6b;">加载失败,请稍后重试</div>';
398
- });
399
- }
400
-
401
- function renderArtifactsList(container, data) {
402
- container.innerHTML = "";
403
- // 拼接: base + workspace前缀 + / + 资源路径
404
- // main → workspace, 其他 → workspace-{name}
405
- var wsName = data.workspace_id || "";
406
- var wsPrefix = wsName === "main" ? "workspace" : "workspace-" + wsName;
407
- var baseUrl = window.location.origin + "/cmd/api/preview?path=" + wsPrefix + "/";
408
-
409
- data.assets.forEach(function (asset) {
410
- var card = document.createElement("a");
411
- card.href = baseUrl + asset.path;
412
- card.target = "_blank";
413
- card.rel = "noopener noreferrer";
414
- card.style.cssText = [
415
- "display: block",
416
- "padding: 12px 14px",
417
- "margin-bottom: 10px",
418
- "background: #2d2d3f",
419
- "border-radius: 6px",
420
- "color: #cdd6f4",
421
- "text-decoration: none",
422
- "transition: background 0.15s",
423
- "cursor: pointer",
424
- ].join(";");
425
- card.onmouseenter = function () { card.style.background = "#3d3d5c"; };
426
- card.onmouseleave = function () { card.style.background = "#2d2d3f"; };
427
-
428
- var title = document.createElement("div");
429
- title.style.cssText = "font-size: 14px; font-weight: bold; margin-bottom: 4px;";
430
- title.textContent = asset.name || "未命名作品";
431
-
432
- var meta = document.createElement("div");
433
- meta.style.cssText = "font-size: 11px; color: #888;";
434
- meta.textContent = asset.type ? asset.type.toUpperCase() : "";
435
-
436
- card.appendChild(title);
437
- card.appendChild(meta);
438
- container.appendChild(card);
439
- });
440
- }
441
-
442
- function closeArtifactsPanel() {
443
- var modal = document.querySelector("#myclaw-artifacts-modal");
444
- if (modal) modal.remove();
445
- artifactsOpen = false;
446
-
447
- var btn = document.querySelector("#myclaw-artifacts-btn");
448
- if (btn) btn.style.background = "rgba(100, 100, 100, 0.7)";
449
- }
450
-
451
231
  // \u6D4B\u8BD5\u9EA6\u514B\u98CE\u51FD\u6570
452
232
  function testMicrophone() {
453
233
  console.log("[myclaw] \u5F00\u59CB\u6D4B\u8BD5\u9EA6\u514B\u98CE...");
@@ -806,7 +586,6 @@
806
586
  createVersionBar();
807
587
  createDocButton();
808
588
  createCmdButton();
809
- createArtifactsButton();
810
589
  injectStyles();
811
590
 
812
591
  // 初始化 VoiceInput SDK
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.196",
3
+ "version": "1.0.197",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
package/patch.js CHANGED
@@ -26,6 +26,7 @@ const INJECT_FILENAME = 'myclaw-inject.js';
26
26
  const VOICE_SDK_FILENAME = 'voice-input.js';
27
27
  const VOICE_OUTPUT_SDK_FILENAME = 'voice-output.js';
28
28
  const TTS_INJECT_FILENAME = 'myclaw-tts.js';
29
+ const ARTIFACTS_INJECT_FILENAME = 'myclaw-artifacts.js';
29
30
  const BACKUP_SUFFIX = '.myclaw-backup';
30
31
 
31
32
  /**
@@ -115,6 +116,8 @@ function patch() {
115
116
  const voiceOutputSdkDest = path.join(uiDir, VOICE_OUTPUT_SDK_FILENAME);
116
117
  const ttsInjectSrc = path.join(__dirname, 'assets', TTS_INJECT_FILENAME);
117
118
  const ttsInjectDest = path.join(uiDir, TTS_INJECT_FILENAME);
119
+ const artifactsInjectSrc = path.join(__dirname, 'assets', ARTIFACTS_INJECT_FILENAME);
120
+ const artifactsInjectDest = path.join(uiDir, ARTIFACTS_INJECT_FILENAME);
118
121
  const version = getMyclawVersion();
119
122
 
120
123
  console.log('[myclaw-patch] → control-ui: ' + uiDir);
@@ -166,6 +169,14 @@ function patch() {
166
169
  console.error('[myclaw-patch] ⚠ TTS 注入脚本复制失败 (非致命): ' + err.message);
167
170
  }
168
171
 
172
+ // 5.5 复制 Artifacts 注入脚本
173
+ try {
174
+ fs.copyFileSync(artifactsInjectSrc, artifactsInjectDest);
175
+ console.log('[myclaw-patch] ✅ Artifacts 注入脚本已复制');
176
+ } catch (err) {
177
+ console.error('[myclaw-patch] ⚠ Artifacts 注入脚本复制失败 (非致命): ' + err.message);
178
+ }
179
+
169
180
  // 6. Patch index.html(幂等)
170
181
  try {
171
182
  let html = fs.readFileSync(indexPath, 'utf8');
@@ -183,6 +194,7 @@ function patch() {
183
194
  '<script src="./' + VOICE_OUTPUT_SDK_FILENAME + '"></script>',
184
195
  '<script src="./' + VOICE_SDK_FILENAME + '"></script>',
185
196
  '<script src="./' + TTS_INJECT_FILENAME + '"></script>',
197
+ '<script src="./' + ARTIFACTS_INJECT_FILENAME + '"></script>',
186
198
  '<script src="./' + INJECT_FILENAME + '"></script>',
187
199
  '',
188
200
  ].join('\n');
@@ -266,6 +278,7 @@ function unpatch() {
266
278
  const voiceSdkDest = path.join(uiDir, VOICE_SDK_FILENAME);
267
279
  const voiceOutputSdkDest = path.join(uiDir, VOICE_OUTPUT_SDK_FILENAME);
268
280
  const ttsInjectDest = path.join(uiDir, TTS_INJECT_FILENAME);
281
+ const artifactsInjectDest = path.join(uiDir, ARTIFACTS_INJECT_FILENAME);
269
282
 
270
283
  // 恢复备份
271
284
  if (fs.existsSync(backupPath)) {
@@ -298,6 +311,12 @@ function unpatch() {
298
311
  console.log('[myclaw-patch] ✅ TTS 注入脚本已删除');
299
312
  }
300
313
 
314
+ // 删除 Artifacts 注入脚本
315
+ if (fs.existsSync(artifactsInjectDest)) {
316
+ fs.unlinkSync(artifactsInjectDest);
317
+ console.log('[myclaw-patch] ✅ Artifacts 注入脚本已删除');
318
+ }
319
+
301
320
  // 恢复 gateway-cli-*.js 的 Permissions-Policy
302
321
  try {
303
322
  const distParent = path.resolve(uiDir, '..');