@kin-tio/cli 0.6.1 → 0.7.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/.env.example +4 -2
- package/CHANGELOG.md +39 -0
- package/README.md +55 -16
- package/README.zh-CN.md +36 -10
- package/assets/avatar.svg +32 -0
- package/assets/logo.svg +22 -0
- package/dist/src/cli.js +245 -4
- package/dist/src/config.js +72 -17
- package/dist/src/ilink/cli-accounts.js +66 -0
- package/dist/src/ilink/cli-login.js +563 -0
- package/dist/src/ilink/cli-start.js +57 -0
- package/dist/src/ilink/enrollment.js +24 -0
- package/dist/src/ilink/login-manager.js +102 -30
- package/dist/src/ilink/login-store.js +78 -29
- package/dist/src/ilink/qr.js +67 -3
- package/dist/src/ilink/secret-box.js +73 -0
- package/dist/src/ilink/sqlite-store.js +211 -13
- package/dist/src/mcp/ilink-login-server.js +160 -0
- package/dist/src/mcp/ipc-host.js +4 -1
- package/dist/src/mcp/ipc-protocol.js +22 -0
- package/dist/src/runtime.js +226 -92
- package/dist/src/services/codex-agent.js +57 -27
- package/dist/src/services/codex-app-server.js +4 -2
- package/dist/src/services/conversation-processor.js +8 -2
- package/dist/src/state/sqlite-store.js +151 -10
- package/dist/src/version.js +1 -1
- package/package.json +3 -1
|
@@ -103,6 +103,9 @@ export class ConversationProcessor {
|
|
|
103
103
|
#conversationKey(record) {
|
|
104
104
|
return `${record.channel}\0${record.accountKey}\0${record.peerId}`;
|
|
105
105
|
}
|
|
106
|
+
#agentAccess(record) {
|
|
107
|
+
return this.#pipeline.agentAccess?.(record) === 'host' ? 'host' : 'restricted';
|
|
108
|
+
}
|
|
106
109
|
#notifyQueued(record) {
|
|
107
110
|
const key = this.#conversationKey(record);
|
|
108
111
|
if (this.#queueNotified.has(key))
|
|
@@ -304,6 +307,7 @@ export class ConversationProcessor {
|
|
|
304
307
|
}
|
|
305
308
|
async #submit(record, input, options = {}) {
|
|
306
309
|
const opaqueConversationId = conversationId(record);
|
|
310
|
+
const agentAccess = this.#agentAccess(record);
|
|
307
311
|
const activePrimary = options.wait
|
|
308
312
|
? undefined
|
|
309
313
|
: this.#pipeline.agent.activePrimary(opaqueConversationId);
|
|
@@ -324,6 +328,7 @@ export class ConversationProcessor {
|
|
|
324
328
|
try {
|
|
325
329
|
const submission = await this.#pipeline.agent.submit({
|
|
326
330
|
...input,
|
|
331
|
+
agentAccess,
|
|
327
332
|
channel: record.channel,
|
|
328
333
|
mode: 'steer',
|
|
329
334
|
conversationId: opaqueConversationId,
|
|
@@ -359,7 +364,7 @@ export class ConversationProcessor {
|
|
|
359
364
|
});
|
|
360
365
|
const boundaryMessageKey = options.boundaryMessageKey || record.messageKey;
|
|
361
366
|
const conversationBefore = this.#store.getConversation(record.channel, record.accountKey, record.peerId);
|
|
362
|
-
const ensuredThreadId = await this.#pipeline.agent.ensureThread(opaqueConversationId, conversationBefore?.threadId || '');
|
|
367
|
+
const ensuredThreadId = await this.#pipeline.agent.ensureThread(opaqueConversationId, conversationBefore?.threadId || '', agentAccess);
|
|
363
368
|
const pendingMemoryThreadId = this.#pipeline.agent.takePendingMemoryThread?.(opaqueConversationId) || '';
|
|
364
369
|
if (!conversationBefore || ensuredThreadId !== conversationBefore.threadId) {
|
|
365
370
|
this.#store.setConversationThread({
|
|
@@ -389,6 +394,7 @@ export class ConversationProcessor {
|
|
|
389
394
|
try {
|
|
390
395
|
submission = await this.#pipeline.agent.submit({
|
|
391
396
|
...input,
|
|
397
|
+
agentAccess,
|
|
392
398
|
channel: record.channel,
|
|
393
399
|
...(artifactCatalog.length ? { artifactCatalog } : {}),
|
|
394
400
|
mode: 'start',
|
|
@@ -668,7 +674,7 @@ export class ConversationProcessor {
|
|
|
668
674
|
const latestId = ids.at(-1) || primary.clientInputId;
|
|
669
675
|
const steering = validGroup.filter((item) => item.status === 'steering');
|
|
670
676
|
const inspection = conversation?.threadId && this.#pipeline.agent.inspectHistory
|
|
671
|
-
? await this.#pipeline.agent.inspectHistory(conversation.threadId, ids, latestId)
|
|
677
|
+
? await this.#pipeline.agent.inspectHistory(conversation.threadId, ids, latestId, this.#agentAccess(primary))
|
|
672
678
|
: undefined;
|
|
673
679
|
const missingInput = steering.some((record) => {
|
|
674
680
|
const clientId = record.clientInputId || record.messageKey;
|
|
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { MAX_WECHAT_IMAGE_BYTES, detectImageFormat, } from '../lib/image-format.js';
|
|
5
5
|
import { ensurePrivateDirectory } from '../lib/private-directory.js';
|
|
6
|
-
const SCHEMA_VERSION =
|
|
6
|
+
const SCHEMA_VERSION = 24;
|
|
7
7
|
const INBOUND_STATUSES = [
|
|
8
8
|
'received',
|
|
9
9
|
'processing',
|
|
@@ -327,8 +327,8 @@ export class SqliteStore {
|
|
|
327
327
|
if (version !== 0 && version !== 11 && version !== 12 &&
|
|
328
328
|
version !== 13 && version !== 14 && version !== 15 &&
|
|
329
329
|
version !== 16 && version !== 17 && version !== 18 && version !== 19 &&
|
|
330
|
-
version !== 20 && version !== 21) {
|
|
331
|
-
throw new Error(`SQLite schema version ${version} is no longer supported; migrate to version 11
|
|
330
|
+
version !== 20 && version !== 21 && version !== 22 && version !== 23) {
|
|
331
|
+
throw new Error(`SQLite schema version ${version} is no longer supported; migrate to version 11 through 23 first`);
|
|
332
332
|
}
|
|
333
333
|
if (version === 11) {
|
|
334
334
|
this.#database.exec(`
|
|
@@ -1384,6 +1384,131 @@ export class SqliteStore {
|
|
|
1384
1384
|
PRAGMA foreign_keys = ON;
|
|
1385
1385
|
`);
|
|
1386
1386
|
}
|
|
1387
|
+
version = 22;
|
|
1388
|
+
}
|
|
1389
|
+
if (version === 22) {
|
|
1390
|
+
this.#database.exec('BEGIN IMMEDIATE');
|
|
1391
|
+
try {
|
|
1392
|
+
const accountColumns = this.#database.prepare('PRAGMA table_info(ilink_accounts)').all();
|
|
1393
|
+
if (!accountColumns.some(({ name }) => name === 'agent_access')) {
|
|
1394
|
+
this.#database.exec(`
|
|
1395
|
+
ALTER TABLE ilink_accounts ADD COLUMN agent_access TEXT NOT NULL
|
|
1396
|
+
DEFAULT 'restricted'
|
|
1397
|
+
CHECK (agent_access IN ('restricted', 'host'));
|
|
1398
|
+
`);
|
|
1399
|
+
}
|
|
1400
|
+
this.#database.exec(`
|
|
1401
|
+
DROP INDEX ilink_one_pending_offer_idx;
|
|
1402
|
+
ALTER TABLE ilink_login_offers RENAME TO ilink_login_offers_v22;
|
|
1403
|
+
CREATE TABLE ilink_login_offers (
|
|
1404
|
+
offer_id TEXT PRIMARY KEY,
|
|
1405
|
+
initiator_kind TEXT NOT NULL
|
|
1406
|
+
CHECK (initiator_kind IN ('local_operator', 'remote_adapter')),
|
|
1407
|
+
source_channel TEXT NOT NULL,
|
|
1408
|
+
source_message_key TEXT NOT NULL,
|
|
1409
|
+
source_account_id TEXT NOT NULL,
|
|
1410
|
+
source_peer_id TEXT NOT NULL,
|
|
1411
|
+
candidate_account_keys_json TEXT NOT NULL DEFAULT '[]'
|
|
1412
|
+
CHECK (json_valid(candidate_account_keys_json)),
|
|
1413
|
+
secret_generation INTEGER NOT NULL CHECK (secret_generation >= 0),
|
|
1414
|
+
nonce TEXT NOT NULL,
|
|
1415
|
+
ciphertext TEXT NOT NULL,
|
|
1416
|
+
auth_tag TEXT NOT NULL,
|
|
1417
|
+
api_base_url TEXT NOT NULL,
|
|
1418
|
+
status TEXT NOT NULL DEFAULT 'waiting'
|
|
1419
|
+
CHECK (status IN (
|
|
1420
|
+
'waiting', 'scanned', 'confirmed', 'expired', 'failed', 'cancelled'
|
|
1421
|
+
)),
|
|
1422
|
+
expires_at INTEGER NOT NULL,
|
|
1423
|
+
last_polled_at INTEGER NOT NULL DEFAULT 0,
|
|
1424
|
+
error_code TEXT NOT NULL DEFAULT '',
|
|
1425
|
+
created_at INTEGER NOT NULL,
|
|
1426
|
+
updated_at INTEGER NOT NULL
|
|
1427
|
+
) STRICT, WITHOUT ROWID;
|
|
1428
|
+
INSERT INTO ilink_login_offers (
|
|
1429
|
+
offer_id, initiator_kind, source_channel, source_message_key,
|
|
1430
|
+
source_account_id, source_peer_id, secret_generation,
|
|
1431
|
+
candidate_account_keys_json,
|
|
1432
|
+
nonce, ciphertext, auth_tag, api_base_url, status,
|
|
1433
|
+
expires_at, last_polled_at, error_code, created_at, updated_at
|
|
1434
|
+
)
|
|
1435
|
+
SELECT
|
|
1436
|
+
offer_id, 'remote_adapter', 'wechat_kf', source_message_key,
|
|
1437
|
+
source_open_kfid, source_external_userid, secret_generation,
|
|
1438
|
+
'[]',
|
|
1439
|
+
nonce, ciphertext, auth_tag, api_base_url, status,
|
|
1440
|
+
expires_at, last_polled_at, error_code, created_at, updated_at
|
|
1441
|
+
FROM ilink_login_offers_v22;
|
|
1442
|
+
DROP TABLE ilink_login_offers_v22;
|
|
1443
|
+
CREATE UNIQUE INDEX ilink_one_pending_offer_idx
|
|
1444
|
+
ON ilink_login_offers(
|
|
1445
|
+
source_channel, source_account_id, source_peer_id
|
|
1446
|
+
)
|
|
1447
|
+
WHERE status IN ('waiting', 'scanned');
|
|
1448
|
+
|
|
1449
|
+
ALTER TABLE ilink_enrollment_audit RENAME TO ilink_enrollment_audit_v22;
|
|
1450
|
+
CREATE TABLE ilink_enrollment_audit (
|
|
1451
|
+
offer_id TEXT PRIMARY KEY,
|
|
1452
|
+
initiator_kind TEXT NOT NULL
|
|
1453
|
+
CHECK (initiator_kind IN ('local_operator', 'remote_adapter')),
|
|
1454
|
+
source_channel TEXT NOT NULL,
|
|
1455
|
+
source_message_key TEXT NOT NULL,
|
|
1456
|
+
source_account_id TEXT NOT NULL,
|
|
1457
|
+
source_peer_id TEXT NOT NULL,
|
|
1458
|
+
account_key TEXT NOT NULL DEFAULT '',
|
|
1459
|
+
result TEXT NOT NULL CHECK (result IN (
|
|
1460
|
+
'confirmed', 'expired', 'failed', 'cancelled',
|
|
1461
|
+
'already_connected', 'verification_required'
|
|
1462
|
+
)),
|
|
1463
|
+
offered_at INTEGER NOT NULL,
|
|
1464
|
+
completed_at INTEGER NOT NULL
|
|
1465
|
+
) STRICT, WITHOUT ROWID;
|
|
1466
|
+
INSERT INTO ilink_enrollment_audit (
|
|
1467
|
+
offer_id, initiator_kind, source_channel, source_message_key,
|
|
1468
|
+
source_account_id, source_peer_id, account_key,
|
|
1469
|
+
result, offered_at, completed_at
|
|
1470
|
+
)
|
|
1471
|
+
SELECT
|
|
1472
|
+
offer_id, 'remote_adapter', 'wechat_kf', source_message_key,
|
|
1473
|
+
source_open_kfid, source_external_userid, account_key,
|
|
1474
|
+
result, offered_at, completed_at
|
|
1475
|
+
FROM ilink_enrollment_audit_v22;
|
|
1476
|
+
DROP TABLE ilink_enrollment_audit_v22;
|
|
1477
|
+
|
|
1478
|
+
PRAGMA user_version = 23;
|
|
1479
|
+
COMMIT;
|
|
1480
|
+
`);
|
|
1481
|
+
}
|
|
1482
|
+
catch (error) {
|
|
1483
|
+
this.#database.exec('ROLLBACK');
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1486
|
+
version = 23;
|
|
1487
|
+
}
|
|
1488
|
+
if (version === 23) {
|
|
1489
|
+
this.#database.exec('BEGIN IMMEDIATE');
|
|
1490
|
+
try {
|
|
1491
|
+
const accountColumns = this.#database.prepare('PRAGMA table_info(ilink_accounts)').all();
|
|
1492
|
+
if (!accountColumns.some(({ name }) => name === 'runtime_enabled')) {
|
|
1493
|
+
this.#database.exec(`
|
|
1494
|
+
ALTER TABLE ilink_accounts ADD COLUMN runtime_enabled INTEGER NOT NULL
|
|
1495
|
+
DEFAULT 0 CHECK (runtime_enabled IN (0, 1));
|
|
1496
|
+
`);
|
|
1497
|
+
}
|
|
1498
|
+
this.#database.exec(`
|
|
1499
|
+
UPDATE ilink_accounts
|
|
1500
|
+
SET runtime_enabled = 1
|
|
1501
|
+
WHERE status = 'active' AND (
|
|
1502
|
+
SELECT COUNT(*) FROM ilink_accounts WHERE status = 'active'
|
|
1503
|
+
) = 1;
|
|
1504
|
+
PRAGMA user_version = 24;
|
|
1505
|
+
COMMIT;
|
|
1506
|
+
`);
|
|
1507
|
+
}
|
|
1508
|
+
catch (error) {
|
|
1509
|
+
this.#database.exec('ROLLBACK');
|
|
1510
|
+
throw error;
|
|
1511
|
+
}
|
|
1387
1512
|
return;
|
|
1388
1513
|
}
|
|
1389
1514
|
this.#database.exec('BEGIN IMMEDIATE');
|
|
@@ -1425,6 +1550,10 @@ export class SqliteStore {
|
|
|
1425
1550
|
generation INTEGER NOT NULL DEFAULT 1 CHECK (generation > 0),
|
|
1426
1551
|
status TEXT NOT NULL DEFAULT 'active'
|
|
1427
1552
|
CHECK (status IN ('active', 'paused', 'disabled', 'revoked')),
|
|
1553
|
+
agent_access TEXT NOT NULL DEFAULT 'restricted'
|
|
1554
|
+
CHECK (agent_access IN ('restricted', 'host')),
|
|
1555
|
+
runtime_enabled INTEGER NOT NULL DEFAULT 0
|
|
1556
|
+
CHECK (runtime_enabled IN (0, 1)),
|
|
1428
1557
|
pause_until INTEGER NOT NULL DEFAULT 0,
|
|
1429
1558
|
cursor TEXT NOT NULL DEFAULT '',
|
|
1430
1559
|
cursor_updated_at INTEGER NOT NULL DEFAULT 0,
|
|
@@ -1448,9 +1577,14 @@ export class SqliteStore {
|
|
|
1448
1577
|
|
|
1449
1578
|
CREATE TABLE ilink_login_offers (
|
|
1450
1579
|
offer_id TEXT PRIMARY KEY,
|
|
1580
|
+
initiator_kind TEXT NOT NULL
|
|
1581
|
+
CHECK (initiator_kind IN ('local_operator', 'remote_adapter')),
|
|
1582
|
+
source_channel TEXT NOT NULL,
|
|
1451
1583
|
source_message_key TEXT NOT NULL,
|
|
1452
|
-
|
|
1453
|
-
|
|
1584
|
+
source_account_id TEXT NOT NULL,
|
|
1585
|
+
source_peer_id TEXT NOT NULL,
|
|
1586
|
+
candidate_account_keys_json TEXT NOT NULL DEFAULT '[]'
|
|
1587
|
+
CHECK (json_valid(candidate_account_keys_json)),
|
|
1454
1588
|
secret_generation INTEGER NOT NULL CHECK (secret_generation >= 0),
|
|
1455
1589
|
nonce TEXT NOT NULL,
|
|
1456
1590
|
ciphertext TEXT NOT NULL,
|
|
@@ -1467,17 +1601,24 @@ export class SqliteStore {
|
|
|
1467
1601
|
updated_at INTEGER NOT NULL
|
|
1468
1602
|
) STRICT, WITHOUT ROWID;
|
|
1469
1603
|
CREATE UNIQUE INDEX ilink_one_pending_offer_idx
|
|
1470
|
-
ON ilink_login_offers(
|
|
1604
|
+
ON ilink_login_offers(
|
|
1605
|
+
source_channel, source_account_id, source_peer_id
|
|
1606
|
+
)
|
|
1471
1607
|
WHERE status IN ('waiting', 'scanned');
|
|
1472
1608
|
|
|
1473
1609
|
CREATE TABLE ilink_enrollment_audit (
|
|
1474
1610
|
offer_id TEXT PRIMARY KEY,
|
|
1611
|
+
initiator_kind TEXT NOT NULL
|
|
1612
|
+
CHECK (initiator_kind IN ('local_operator', 'remote_adapter')),
|
|
1613
|
+
source_channel TEXT NOT NULL,
|
|
1475
1614
|
source_message_key TEXT NOT NULL,
|
|
1476
|
-
|
|
1477
|
-
|
|
1615
|
+
source_account_id TEXT NOT NULL,
|
|
1616
|
+
source_peer_id TEXT NOT NULL,
|
|
1478
1617
|
account_key TEXT NOT NULL DEFAULT '',
|
|
1479
|
-
result TEXT NOT NULL
|
|
1480
|
-
|
|
1618
|
+
result TEXT NOT NULL CHECK (result IN (
|
|
1619
|
+
'confirmed', 'expired', 'failed', 'cancelled',
|
|
1620
|
+
'already_connected', 'verification_required'
|
|
1621
|
+
)),
|
|
1481
1622
|
offered_at INTEGER NOT NULL,
|
|
1482
1623
|
completed_at INTEGER NOT NULL
|
|
1483
1624
|
) STRICT, WITHOUT ROWID;
|
package/dist/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const KINTIO_VERSION = '0.
|
|
1
|
+
export const KINTIO_VERSION = '0.7.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kin-tio/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "XIE YU",
|
|
6
6
|
"packageManager": "pnpm@10.34.5",
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"bin/kintio.js",
|
|
18
18
|
"dist",
|
|
19
|
+
"assets/avatar.svg",
|
|
20
|
+
"assets/logo.svg",
|
|
19
21
|
"assets/ilink-login-card.png",
|
|
20
22
|
"codex-workspace/.agents/skills/wechat-kf-reply-sop/SKILL.md",
|
|
21
23
|
".env.example",
|