@11agents/cli 0.1.41 → 0.1.43
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/mobile-runtime/python/src/device_control/cli.py +17 -2
- package/mobile-runtime/python/src/device_control/metrics/tiktok_video_adb.py +8 -3
- package/mobile-runtime/python/src/device_control/publishers/tiktok_adb.py +679 -12
- package/mobile-runtime/python/src/device_control/publishers/tiktok_appium.py +173 -14
- package/mobile-runtime/python/src/device_control/publishers/x_adb.py +319 -5
- package/mobile-runtime/skills/android-collect-tiktok-metrics/SKILL.md +76 -0
- package/mobile-runtime/skills/android-publish-tiktok/SKILL.md +3 -3
- package/mobile-runtime/skills/android-publish-x/SKILL.md +5 -1
- package/mobile-runtime/skills/android-publish-xiaohongshu/SKILL.md +1 -1
- package/mobile-runtime/skills/mobile-publish-data-collection/SKILL.md +79 -3
- package/mobile-runtime/skills/mobile-publish-execution/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/commands/knowledge.js +23 -1
- package/src/commands/mobile.js +29 -6
- package/src/commands/runtime.js +4 -1
- package/src/schema.js +5 -2
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises'
|
|
1
|
+
import { mkdir, readFile, readdir, rm, rmdir, writeFile } from 'node:fs/promises'
|
|
2
2
|
import os from 'node:os'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { flag } from '../args.js'
|
|
@@ -116,6 +116,27 @@ export function buildKnowledgeBaseDir(project, { homeDir = os.homedir() } = {})
|
|
|
116
116
|
return path.join(homeDir, '.11agents', slugify(project), 'knowledge_base')
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
// Mirror the skill-sync strategy: after a sync the cloud snapshot is the source
|
|
120
|
+
// of truth, so local knowledge text files missing from it are removed. Scope is
|
|
121
|
+
// strictly the project's knowledge_base directory.
|
|
122
|
+
async function pruneLocalKnowledgeFiles(baseDir, keepPaths) {
|
|
123
|
+
for (const localPath of await listKnowledgeTextFiles(baseDir)) {
|
|
124
|
+
if (keepPaths.has(localPath)) continue
|
|
125
|
+
await rm(path.join(baseDir, localPath), { force: true })
|
|
126
|
+
}
|
|
127
|
+
const removeEmptyDirs = async dir => {
|
|
128
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => [])
|
|
129
|
+
for (const entry of entries) {
|
|
130
|
+
if (entry.isDirectory()) await removeEmptyDirs(path.join(dir, entry.name))
|
|
131
|
+
}
|
|
132
|
+
if (dir !== baseDir) {
|
|
133
|
+
const remaining = await readdir(dir).catch(() => ['keep'])
|
|
134
|
+
if (remaining.length === 0) await rmdir(dir).catch(() => {})
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
await removeEmptyDirs(baseDir)
|
|
138
|
+
}
|
|
139
|
+
|
|
119
140
|
export async function writeKnowledgeSnapshot(project, snapshot, { homeDir = os.homedir() } = {}) {
|
|
120
141
|
const normalized = normalizeSnapshot(snapshot)
|
|
121
142
|
const baseDir = buildKnowledgeBaseDir(project, { homeDir })
|
|
@@ -138,6 +159,7 @@ export async function writeKnowledgeSnapshot(project, snapshot, { homeDir = os.h
|
|
|
138
159
|
await mkdir(path.dirname(target), { recursive: true })
|
|
139
160
|
await writeFile(target, markdownForNode(node))
|
|
140
161
|
}
|
|
162
|
+
await pruneLocalKnowledgeFiles(baseDir, new Set(normalized.nodes.map(node => node.local_path)))
|
|
141
163
|
return index
|
|
142
164
|
}
|
|
143
165
|
|
package/src/commands/mobile.js
CHANGED
|
@@ -65,8 +65,10 @@ const COMMAND_ALIASES = new Map([
|
|
|
65
65
|
|
|
66
66
|
const WRAPPER_FLAG_NAMES = new Set([
|
|
67
67
|
'mobile-home',
|
|
68
|
+
'project',
|
|
68
69
|
'task-id',
|
|
69
70
|
'task-title',
|
|
71
|
+
'workspace',
|
|
70
72
|
])
|
|
71
73
|
|
|
72
74
|
const EMPTY_DATA_FILES = [
|
|
@@ -99,7 +101,7 @@ Runtime:
|
|
|
99
101
|
Python/device-control code is bundled with @11agents/cli.
|
|
100
102
|
Mutable runtime state lives in ~/.11agents/mobile by default.
|
|
101
103
|
Every command writes logs under ~/.11agents/mobile/runs/<task_id>/log.
|
|
102
|
-
Xiaohongshu/TikTok publish-success DingTalk notification is enabled by
|
|
104
|
+
X/Xiaohongshu/TikTok publish-success DingTalk notification is enabled by
|
|
103
105
|
ELEVENAGENTS_PUBLISH_DINGTALK_WEBHOOK and optional
|
|
104
106
|
ELEVENAGENTS_PUBLISH_DINGTALK_SECRET.`)
|
|
105
107
|
}
|
|
@@ -602,10 +604,12 @@ function buildRunContext(rawArgs, deps = {}) {
|
|
|
602
604
|
|| env.ELEVENAGENTS_ISSUE_TITLE
|
|
603
605
|
|| taskId
|
|
604
606
|
).trim()
|
|
607
|
+
const project = projectFromMobileContext(flags, env)
|
|
605
608
|
const runDir = path.join(home, 'runs', taskId)
|
|
606
609
|
return {
|
|
607
610
|
flags,
|
|
608
611
|
home,
|
|
612
|
+
project,
|
|
609
613
|
taskId,
|
|
610
614
|
taskTitle,
|
|
611
615
|
runDir,
|
|
@@ -613,6 +617,20 @@ function buildRunContext(rawArgs, deps = {}) {
|
|
|
613
617
|
}
|
|
614
618
|
}
|
|
615
619
|
|
|
620
|
+
function projectFromMobileContext(flags = {}, env = process.env) {
|
|
621
|
+
return String(
|
|
622
|
+
flag(flags, 'project')
|
|
623
|
+
|| flag(flags, 'workspace')
|
|
624
|
+
|| env.ELEVENAGENTS_PROJECT_SLUG
|
|
625
|
+
|| env.ELEVENAGENTS_PROJECT
|
|
626
|
+
|| env.ELEVENAGENTS_PROJECT_NAME
|
|
627
|
+
|| env.ELEVENAGENTS_WORKSPACE_SLUG
|
|
628
|
+
|| env.GTM_SWARM_WORKSPACE
|
|
629
|
+
|| env.WORKSPACE_SLUG
|
|
630
|
+
|| ''
|
|
631
|
+
).trim()
|
|
632
|
+
}
|
|
633
|
+
|
|
616
634
|
async function dispatchPython(rawArgs, deps = {}) {
|
|
617
635
|
const command = normalizePythonCommand(rawArgs[0] || '')
|
|
618
636
|
if (!PYTHON_COMMANDS.has(command)) throw new Error(`unsupported mobile command: ${rawArgs[0] || ''}`)
|
|
@@ -622,6 +640,7 @@ async function dispatchPython(rawArgs, deps = {}) {
|
|
|
622
640
|
const env = pythonEnv(context.home, deps.env || process.env)
|
|
623
641
|
env.ELEVENAGENTS_MOBILE_RUN_DIR = context.runDir
|
|
624
642
|
env.ELEVENAGENTS_TASK_ID = context.taskId
|
|
643
|
+
if (context.project) env.ELEVENAGENTS_PROJECT_SLUG = context.project
|
|
625
644
|
const result = await runAndLog({
|
|
626
645
|
command: python,
|
|
627
646
|
args: childArgs,
|
|
@@ -661,6 +680,7 @@ async function dispatchScript(rawArgs, deps = {}) {
|
|
|
661
680
|
const env = pythonEnv(context.home, deps.env || process.env)
|
|
662
681
|
env.ELEVENAGENTS_MOBILE_RUN_DIR = context.runDir
|
|
663
682
|
env.ELEVENAGENTS_TASK_ID = context.taskId
|
|
683
|
+
if (context.project) env.ELEVENAGENTS_PROJECT_SLUG = context.project
|
|
664
684
|
const result = await runAndLog({
|
|
665
685
|
command: python,
|
|
666
686
|
args: [scriptPath, ...stripWrapperFlags(rawArgs.slice(1))],
|
|
@@ -702,6 +722,7 @@ async function notifyMobilePublishSuccess({ command, context, parsed, env = proc
|
|
|
702
722
|
const link = publishResultLink(row)
|
|
703
723
|
const content = buildPublishNotificationContent({
|
|
704
724
|
platform,
|
|
725
|
+
project: context.project,
|
|
705
726
|
task: context.taskTitle || context.taskId,
|
|
706
727
|
deviceId: row.device_id || row.device || '',
|
|
707
728
|
link,
|
|
@@ -755,7 +776,7 @@ function isPublishedResult(row) {
|
|
|
755
776
|
}
|
|
756
777
|
|
|
757
778
|
function shouldNotifyPublishPlatform(platform) {
|
|
758
|
-
return platform === 'xiaohongshu' || platform === 'tiktok'
|
|
779
|
+
return platform === 'xiaohongshu' || platform === 'tiktok' || platform === 'x'
|
|
759
780
|
}
|
|
760
781
|
|
|
761
782
|
function publishResultLink(row) {
|
|
@@ -768,13 +789,14 @@ function publishResultLink(row) {
|
|
|
768
789
|
).trim()
|
|
769
790
|
}
|
|
770
791
|
|
|
771
|
-
function buildPublishNotificationContent({ platform, task, deviceId = '', link }) {
|
|
792
|
+
function buildPublishNotificationContent({ platform, project = '', task, deviceId = '', link }) {
|
|
772
793
|
const label = platformLabel(platform)
|
|
794
|
+
const projectText = String(project || '').trim()
|
|
773
795
|
const taskText = String(task || 'task').trim()
|
|
774
796
|
const deviceText = deviceId ? `(设备 ${deviceId})` : ''
|
|
775
|
-
|
|
776
|
-
const
|
|
777
|
-
return `${label} ${taskText}${deviceText}已发布,链接:${linkText}`
|
|
797
|
+
const linkText = String(link || '').trim() || '未收集到'
|
|
798
|
+
const prefix = projectText ? `[${projectText}] ` : ''
|
|
799
|
+
return `${prefix}${label} ${taskText}${deviceText}已发布,链接:${linkText}`
|
|
778
800
|
}
|
|
779
801
|
|
|
780
802
|
function platformLabel(platform) {
|
|
@@ -946,6 +968,7 @@ export const mobileInternals = {
|
|
|
946
968
|
mobileHome,
|
|
947
969
|
parseRawArgs,
|
|
948
970
|
platformFromMobileCommand,
|
|
971
|
+
projectFromMobileContext,
|
|
949
972
|
publishResultLink,
|
|
950
973
|
shouldNotifyPublishPlatform,
|
|
951
974
|
signedDingTalkUrl,
|
package/src/commands/runtime.js
CHANGED
|
@@ -1124,10 +1124,13 @@ async function prepareRuntimeTask(task, flags, deps, config) {
|
|
|
1124
1124
|
// Resolve project token before skill sync so MCP auth is available.
|
|
1125
1125
|
const projectToken = await projectSyncToken(projectTokenCandidatesForTask(task, flags), flags, deps, task.workspace?.swarm_token)
|
|
1126
1126
|
const skills = await syncSkillsViaMcp({ task, workdir, flags, deps, projectToken, config })
|
|
1127
|
+
const projectSlug = projectSlugForTask(task, flags)
|
|
1127
1128
|
const env = {
|
|
1128
1129
|
...process.env,
|
|
1129
1130
|
...agentEnvironment(task),
|
|
1130
1131
|
ELEVENAGENTS_PROJECT_DIR: workdir,
|
|
1132
|
+
ELEVENAGENTS_PROJECT_SLUG: projectSlug,
|
|
1133
|
+
ELEVENAGENTS_PROJECT_NAME: String(task.workspace?.name || task.workspace?.slug || task.workspace_slug || ''),
|
|
1131
1134
|
ELEVENAGENTS_AGENT_DIR: agentDir,
|
|
1132
1135
|
ELEVENAGENTS_AGENT_SKILLS_DIR: agentSkillsDir,
|
|
1133
1136
|
ELEVENAGENTS_AGENT_MEMORY_DIR: agentMemoryDir,
|
|
@@ -1146,7 +1149,7 @@ async function prepareRuntimeTask(task, flags, deps, config) {
|
|
|
1146
1149
|
agent_results_dir: agentResultsDir,
|
|
1147
1150
|
tmp_dir: tmpDir,
|
|
1148
1151
|
run_dir: runDir,
|
|
1149
|
-
project_slug:
|
|
1152
|
+
project_slug: projectSlug,
|
|
1150
1153
|
readonly: true,
|
|
1151
1154
|
env,
|
|
1152
1155
|
database,
|
package/src/schema.js
CHANGED
|
@@ -26,7 +26,9 @@ export function validateTelemetryBatch(input) {
|
|
|
26
26
|
}
|
|
27
27
|
const artifacts = Array.isArray(input.artifacts) ? input.artifacts : []
|
|
28
28
|
const observations = Array.isArray(input.observations) ? input.observations : []
|
|
29
|
-
if (!artifacts.length && !observations.length
|
|
29
|
+
if (!artifacts.length && !observations.length && !isObject(input.dashboard_spec)) {
|
|
30
|
+
return fail('artifacts, observations, or dashboard_spec are required')
|
|
31
|
+
}
|
|
30
32
|
for (let i = 0; i < artifacts.length; i += 1) {
|
|
31
33
|
const item = artifacts[i]
|
|
32
34
|
for (const field of ['platform', 'artifact_type', 'external_id', 'created_at']) {
|
|
@@ -48,7 +50,7 @@ export function validateTelemetryBatch(input) {
|
|
|
48
50
|
return { ok: true, batch: { ...input, agent_id: agentId.trim() } }
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
export function buildTelemetryBatch({ workspace, agent_id, agent_key, node_id, artifacts = [], observations = [] }) {
|
|
53
|
+
export function buildTelemetryBatch({ workspace, agent_id, agent_key, node_id, artifacts = [], observations = [], dashboard_spec = null }) {
|
|
52
54
|
return {
|
|
53
55
|
schema_version: TELEMETRY_SCHEMA_VERSION,
|
|
54
56
|
workspace,
|
|
@@ -58,5 +60,6 @@ export function buildTelemetryBatch({ workspace, agent_id, agent_key, node_id, a
|
|
|
58
60
|
sent_at: new Date().toISOString(),
|
|
59
61
|
artifacts,
|
|
60
62
|
observations,
|
|
63
|
+
...(dashboard_spec ? { dashboard_spec } : {}),
|
|
61
64
|
}
|
|
62
65
|
}
|