wtt-connect 0.2.64 → 0.2.65

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wtt-connect",
3
- "version": "0.2.64",
3
+ "version": "0.2.65",
4
4
  "private": false,
5
5
  "description": "WTT-native connector daemon for Codex, Claude Code, Cursor, Gemini, ACP, and other coding agent surfaces.",
6
6
  "type": "module",
package/src/main.js CHANGED
@@ -10,6 +10,7 @@ import { smokeChat, smokeTask } from './smoke.js';
10
10
  import { ArtifactManager } from './artifacts.js';
11
11
  import { DurableStore } from './store.js';
12
12
  import { WTTClient } from './wtt-client.js';
13
+ import { WTTApi } from './wtt-api.js';
13
14
  import { log, redact } from './logger.js';
14
15
  import { adapterBin, normalizeProfileName } from './adapters/generic-cli.js';
15
16
  import { normalizeAdapterName } from './adapters/index.js';
@@ -38,6 +39,7 @@ export async function main(args) {
38
39
  if (cmd === 'upload-artifact' || cmd === 'opendesign-upload') return uploadArtifact(loadConfig(argv), argv);
39
40
  if (cmd === 'preview-port' || cmd === 'sandbox-preview') return previewPort(loadConfig(argv), argv);
40
41
  if (cmd === 'cleanup-previews' || cmd === 'preview-cleanup') return cleanupPreviewsCommand(loadConfig(argv), argv);
42
+ if (cmd === 'feishu' || cmd === 'lark') return feishuCommand(loadConfig(argv), argv);
41
43
  if (cmd === 'start') {
42
44
  const config = loadConfig(argv);
43
45
  if (!config.agentId) throw new Error('WTT_AGENT_ID is required');
@@ -92,6 +94,9 @@ function parseArgs(args) {
92
94
  else if (a === '--source') out.source = args[++i];
93
95
  else if (a === '--source-id') out.sourceId = args[++i];
94
96
  else if (a === '--title') out.title = args[++i];
97
+ else if (a === '--content') out.content = args[++i];
98
+ else if (a === '--folder-token') out.folderToken = args[++i];
99
+ else if (a === '--max-chars') out.maxChars = Number(args[++i]);
95
100
  else if (a === '--entry') out.entry = args[++i];
96
101
  else if (a === '--type') out.type = args[++i];
97
102
  else if (a === '--port') out.port = Number(args[++i]);
@@ -151,10 +156,62 @@ Commands:
151
156
  Create a Cloud Sandbox live preview URL; snapshots are opt-in
152
157
  cleanup-previews [--keep-last <n>]
153
158
  Stop preview servers previously registered by this agent
159
+ feishu read-doc <url-or-token> [--max-chars n]
160
+ Read a Feishu/Lark doc shared with the WTT Bot
161
+ feishu create-doc --title <title> [--content text|--file path] [--folder-token token]
162
+ Create a Feishu/Lark doc through the WTT Bot
163
+ feishu append-doc <url-or-token> (--content text|--file path)
164
+ Append text to a Feishu/Lark doc through the WTT Bot
154
165
  help Show this help
155
166
  `);
156
167
  }
157
168
 
169
+ async function feishuCommand(config, argv) {
170
+ const subcommand = String(argv._[0] || '').trim().toLowerCase();
171
+ const api = new WTTApi(config);
172
+ if (!config.agentId) throw new Error('WTT_AGENT_ID is required');
173
+ if (!config.token) throw new Error('WTT_TOKEN or WTT_AGENT_TOKEN is required');
174
+ if (subcommand === 'read-doc' || subcommand === 'read') {
175
+ const urlOrToken = String(argv._[1] || argv.url || argv.token || '').trim();
176
+ if (!urlOrToken) throw new Error('feishu read-doc requires <url-or-token>');
177
+ const result = await api.feishuReadDoc({ urlOrToken, maxChars: argv.maxChars });
178
+ console.log(JSON.stringify(result, null, 2));
179
+ return;
180
+ }
181
+ if (subcommand === 'create-doc' || subcommand === 'create') {
182
+ const title = String(argv.title || '').trim();
183
+ if (!title) throw new Error('feishu create-doc requires --title <title>');
184
+ const content = readCommandContent(argv);
185
+ const result = await api.feishuCreateDoc({ title, content, folderToken: argv.folderToken || '' });
186
+ console.log(JSON.stringify(result, null, 2));
187
+ return;
188
+ }
189
+ if (subcommand === 'append-doc' || subcommand === 'append') {
190
+ const urlOrToken = String(argv._[1] || argv.url || argv.token || '').trim();
191
+ if (!urlOrToken) throw new Error('feishu append-doc requires <url-or-token>');
192
+ const content = readCommandContent(argv);
193
+ if (!content.trim()) throw new Error('feishu append-doc requires --content <text> or --file <path>');
194
+ const result = await api.feishuAppendDoc({ urlOrToken, content });
195
+ console.log(JSON.stringify(result, null, 2));
196
+ return;
197
+ }
198
+ throw new Error([
199
+ 'unknown feishu command',
200
+ 'Usage:',
201
+ ' wtt-connect feishu read-doc <url-or-token> [--max-chars n]',
202
+ ' wtt-connect feishu create-doc --title <title> [--content text|--file path] [--folder-token token]',
203
+ ' wtt-connect feishu append-doc <url-or-token> (--content text|--file path)',
204
+ ].join('\n'));
205
+ }
206
+
207
+ function readCommandContent(argv) {
208
+ if (typeof argv.content === 'string') return argv.content;
209
+ const file = Array.isArray(argv.files) ? argv.files[0] : '';
210
+ if (!file) return '';
211
+ const resolved = path.resolve(String(file));
212
+ return fs.readFileSync(resolved, 'utf8');
213
+ }
214
+
158
215
  async function previewPort(config, argv) {
159
216
  const port = Number(argv.port || argv._[0]);
160
217
  if (!Number.isInteger(port) || port < 1024 || port > 65535 || port === 3000) {
package/src/runner.js CHANGED
@@ -254,6 +254,7 @@ export class Runner {
254
254
  staged.promptBlock,
255
255
  renderTranscriptBlock(transcripts),
256
256
  renderCloudSandboxStorageInstruction(this.config, topicId),
257
+ renderFeishuToolInstruction(this.config),
257
258
  renderGeneratedFileArtifactInstruction(this.config, topicId),
258
259
  'Reply naturally and concisely unless the user asks for detail.',
259
260
  ].filter(Boolean).join('\n');
@@ -1142,6 +1143,21 @@ function renderGeneratedFileArtifactInstruction(config, topicId = '') {
1142
1143
  ].join('\n');
1143
1144
  }
1144
1145
 
1146
+ function renderFeishuToolInstruction(config) {
1147
+ if (!config.agentId || !config.token) return '';
1148
+ return [
1149
+ 'Feishu/Lark document tool rule, for internal execution only:',
1150
+ '- If the user asks you to read, summarize, analyze, create, or append a Feishu/Lark document, or provides a docs.feishu.cn / feishu.cn / larksuite.com docx/wiki link, call the local WTT Feishu tool instead of guessing from the URL.',
1151
+ '- Read a document: `wtt-connect feishu read-doc "<feishu_doc_or_wiki_url>" --max-chars 50000`.',
1152
+ '- Create a document: `wtt-connect feishu create-doc --title "Title" --content "text"` or put larger content in a file and use `--file path`.',
1153
+ '- Append to a document: `wtt-connect feishu append-doc "<feishu_doc_or_wiki_url>" --content "text"` or `--file path`.',
1154
+ '- The backend only proxies explicit tool calls; do not claim you accessed a Feishu document unless the command succeeds.',
1155
+ '- If the command returns a permission error, tell the user to share the document with the WTT Bot or grant the WTT Feishu app cloud document permissions.',
1156
+ '- The first version intentionally supports read/create/append only. Do not attempt destructive delete, clear, or overwrite operations.',
1157
+ '- When the user explicitly asks to write/create/append a Feishu document, proceed without asking for an extra confirmation.',
1158
+ ].join('\n');
1159
+ }
1160
+
1145
1161
  function renderCloudSandboxStorageInstruction(config, topicId = '') {
1146
1162
  if (!config.cloudSandbox) return '';
1147
1163
  const workDir = config.workDir || process.cwd();
@@ -1645,6 +1661,7 @@ function buildTaskPrompt(task, config, staged = { promptBlock: '' }, transcripts
1645
1661
  '',
1646
1662
  config.requireCommitPush ? 'For code changes, commit and push before final response, and include commit id.' : '',
1647
1663
  renderCloudSandboxStorageInstruction(config, task.topic_id || task.topicId || ''),
1664
+ renderFeishuToolInstruction(config),
1648
1665
  renderGeneratedFileArtifactInstruction(config, task.topic_id || task.topicId || ''),
1649
1666
  'Return a concise final summary with evidence, changed files, tests, artifacts, and blockers.',
1650
1667
  ].filter(Boolean).join('\n');
package/src/wtt-api.js CHANGED
@@ -130,4 +130,38 @@ export class WTTApi {
130
130
  }
131
131
  }
132
132
 
133
+ async feishuReadDoc({ urlOrToken, maxChars } = {}) {
134
+ return this.request('POST', '/integrations/feishu/agent/doc/read', {
135
+ headers: this.agentHeaders(),
136
+ json: {
137
+ agent_id: this.config.agentId,
138
+ url_or_token: urlOrToken,
139
+ ...(maxChars ? { max_chars: Number(maxChars) } : {}),
140
+ },
141
+ });
142
+ }
143
+
144
+ async feishuCreateDoc({ title, content = '', folderToken = '' } = {}) {
145
+ return this.request('POST', '/integrations/feishu/agent/doc/create', {
146
+ headers: this.agentHeaders(),
147
+ json: {
148
+ agent_id: this.config.agentId,
149
+ title,
150
+ content,
151
+ ...(folderToken ? { folder_token: folderToken } : {}),
152
+ },
153
+ });
154
+ }
155
+
156
+ async feishuAppendDoc({ urlOrToken, content } = {}) {
157
+ return this.request('POST', '/integrations/feishu/agent/doc/append', {
158
+ headers: this.agentHeaders(),
159
+ json: {
160
+ agent_id: this.config.agentId,
161
+ url_or_token: urlOrToken,
162
+ content,
163
+ },
164
+ });
165
+ }
166
+
133
167
  }