@thinkingai/ae-cli 6.0.52 → 6.0.54
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 +35 -10
- package/README.zh.md +32 -10
- package/bin/ae-cli.js +6 -1
- package/cli-installation-guide.md +91 -0
- package/dist/{auth-XZNXFRJS.js → auth-MBWRZTB6.js} +171 -13
- package/dist/automation-NWWVLWG2.js +459 -0
- package/dist/{capability-RJZ4KRGP.js → capability-7SSN6PNZ.js} +11 -6
- package/dist/chunk-4655PUNX.js +43 -0
- package/dist/{chunk-4NRCTUZJ.js → chunk-5XJYLEVC.js} +4 -4
- package/dist/{chunk-JOCDD4ON.js → chunk-7QXISROD.js} +1 -1
- package/dist/{chunk-EQ255HKO.js → chunk-AP7YP2NX.js} +2 -2
- package/dist/{chunk-DVMLWQD4.js → chunk-CT7QDJS6.js} +2 -2
- package/dist/chunk-D6ACFILC.js +56 -0
- package/dist/{chunk-HFGZGYCG.js → chunk-EOYSKMXN.js} +264 -10
- package/dist/{chunk-57RRFUEZ.js → chunk-FMNNGNYO.js} +43 -8
- package/dist/{chunk-7XGFSUOM.js → chunk-GIK6EDUG.js} +291 -84
- package/dist/{chunk-WEPZ5M3Z.js → chunk-HBLK3ZHW.js} +7 -4
- package/dist/chunk-HVHR4SCP.js +133 -0
- package/dist/{chunk-DX5CDO34.js → chunk-KFNMQTZI.js} +580 -214
- package/dist/{chunk-HBGADCKA.js → chunk-PLE722AJ.js} +28 -11
- package/dist/chunk-RK6GLDGI.js +27 -0
- package/dist/{chunk-V2NUHPXF.js → chunk-S6M42KND.js} +1 -1
- package/dist/{chunk-7FTTULED.js → chunk-UQ77JXYH.js} +7 -3
- package/dist/{chunk-MAPZ7VB6.js → chunk-WNGFSIOB.js} +20 -1
- package/dist/{chunk-L2QUIZTS.js → chunk-ZIQWCZTS.js} +3 -3
- package/dist/{community-report-client-CU22W53K.js → community-report-client-PEERQCX2.js} +1 -1
- package/dist/{config-XO3LI3SA.js → config-FF6YVJKI.js} +29 -10
- package/dist/context-YAE3QXP3.js +136 -0
- package/dist/{data-integration-HNGUKFIC.js → data-integration-HESZET7E.js} +6 -6
- package/dist/index.js +169 -55
- package/dist/{local-data-upload-client-GTRIT64F.js → local-data-upload-client-TWMHFLUA.js} +1 -1
- package/dist/memory-62BJOULV.js +580 -0
- package/dist/{metadata-JAQW7KGZ.js → metadata-7CUMWIB4.js} +7 -7
- package/dist/{model-RNPQXIBI.js → model-SBV2JFJI.js} +9 -5
- package/dist/{personal-semantic-preference-QCZ2IZTK.js → personal-semantic-preference-6SRCYPGE.js} +119 -11
- package/dist/{project-semantic-64JURXKF.js → project-semantic-YYEM4OSU.js} +7 -7
- package/dist/{sync-O45NXEQY.js → sync-SU33KYX7.js} +12 -8
- package/dist/{te-agent-K5MSPNHJ.js → te-agent-F5QBZSQA.js} +423 -494
- package/dist/{te-analysis-KQKCAI5H.js → te-analysis-U4I2W2WC.js} +1090 -67
- package/dist/{te-community-4OYU3BDA.js → te-community-PFLDLPP4.js} +3 -3
- package/dist/{te-dataops-NFIPB6FX.js → te-dataops-FOQSRIAZ.js} +644 -276
- package/dist/{te-engage-HSVSRW22.js → te-engage-ZX76CNAB.js} +6 -6
- package/dist/{te-kb-3TS73NO6.js → te-kb-MHDOST62.js} +666 -244
- package/dist/{te-system-STMHLS5J.js → te-system-J2FQF5ER.js} +6 -6
- package/dist/{te-team-3I5AOX3N.js → te-team-5UOZPTU3.js} +6 -6
- package/dist/things-VPPXXLHB.js +1091 -0
- package/dist/{update-RZXLPCRH.js → update-EEUTEI6R.js} +59 -51
- package/dist/workspace-O3EEIYQM.js +554 -0
- package/package.json +30 -11
- package/skills/ae-agent/SKILL.md +95 -140
- package/skills/ae-agent/references/add-model.md +1 -1
- package/skills/ae-agent/references/create-agent.md +1 -1
- package/skills/ae-agent/references/find-archived-conversations.md +12 -5
- package/skills/ae-agent/references/get-agent.md +1 -1
- package/skills/ae-agent/references/list-agents.md +2 -2
- package/skills/ae-agent/references/list-models.md +2 -2
- package/skills/ae-agent/references/notification.md +40 -0
- package/skills/ae-agent/references/restore-conversation.md +3 -1
- package/skills/ae-analysis/SKILL.md +76 -15
- package/skills/ae-analysis/references/agent_review_submit_to_page.md +2 -0
- package/skills/ae-analysis/references/ai_models/event.md +6 -1
- package/skills/ae-analysis/references/ai_models/funnel.md +12 -4
- package/skills/ae-analysis/references/ai_models/heat_map.md +23 -0
- package/skills/ae-analysis/references/ai_models/interval.md +24 -0
- package/skills/ae-analysis/references/ai_models/path.md +20 -0
- package/skills/ae-analysis/references/ai_models/prop_analysis.md +2 -0
- package/skills/ae-analysis/references/ai_models/rank_list.md +30 -0
- package/skills/ae-analysis/references/ai_models/retention.md +45 -1
- package/skills/ae-analysis/references/ai_models/revenue.md +20 -2
- package/skills/ae-analysis/references/ai_models/tag.md +2 -0
- package/skills/ae-analysis/references/ai_models.md +96 -0
- package/skills/ae-analysis/references/analysis_data_retrieval.md +4 -0
- package/skills/ae-analysis/references/asset_batch_info_export.md +10 -0
- package/skills/ae-analysis/references/asset_batch_sql_export.md +13 -1
- package/skills/ae-analysis/references/asset_export.md +12 -1
- package/skills/ae-analysis/references/asset_list.md +1 -0
- package/skills/ae-analysis/references/asset_search.md +11 -5
- package/skills/ae-analysis/references/bi_panel_list.md +1 -1
- package/skills/ae-analysis/references/catalog_list.md +1 -1
- package/skills/ae-analysis/references/collaboration.md +48 -0
- package/skills/ae-analysis/references/command_index.md +26 -17
- package/skills/ae-analysis/references/dashboard_list.md +4 -4
- package/skills/ae-analysis/references/dashboard_move.md +21 -0
- package/skills/ae-analysis/references/dashboard_report_add.md +2 -0
- package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
- package/skills/ae-analysis/references/dashboard_report_get.md +19 -0
- package/skills/ae-analysis/references/dashboard_report_update.md +27 -0
- package/skills/ae-analysis/references/dashboard_update.md +1 -1
- package/skills/ae-analysis/references/event_export.md +3 -1
- package/skills/ae-analysis/references/event_report_presentation.md +76 -0
- package/skills/ae-analysis/references/feedback_submit.md +37 -0
- package/skills/ae-analysis/references/governance_recommendation_auto_review.md +71 -0
- package/skills/ae-analysis/references/governance_recommendation_export.md +11 -0
- package/skills/ae-analysis/references/metadata_resolution.md +18 -3
- package/skills/ae-analysis/references/metric_export.md +3 -1
- package/skills/ae-analysis/references/metric_list.md +1 -1
- package/skills/ae-analysis/references/operation_record_export.md +10 -0
- package/skills/ae-analysis/references/personal_semantic_preference_add.md +2 -2
- package/skills/ae-analysis/references/personal_semantic_preference_get.md +6 -4
- package/skills/ae-analysis/references/personal_semantic_preference_list.md +5 -3
- package/skills/ae-analysis/references/personal_semantic_preference_review.md +9 -0
- package/skills/ae-analysis/references/personal_semantic_preference_review_list.md +7 -0
- package/skills/ae-analysis/references/personal_semantic_preference_submit.md +7 -0
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +91 -32
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +99 -1
- package/skills/ae-analysis/references/property_export.md +3 -1
- package/skills/ae-analysis/references/report_create.md +17 -3
- package/skills/ae-analysis/references/report_data_export.md +6 -0
- package/skills/ae-analysis/references/report_get.md +7 -1
- package/skills/ae-analysis/references/report_list.md +5 -5
- package/skills/ae-analysis/references/report_update.md +20 -3
- package/skills/ae-analysis/references/sql_table_columns.md +4 -4
- package/skills/ae-analysis/references/sql_table_list.md +5 -5
- package/skills/ae-analysis/references/system_query_monitor_overview.md +2 -0
- package/skills/ae-analysis/references/system_query_task_cancel.md +2 -0
- package/skills/ae-analysis/references/system_query_task_export.md +6 -2
- package/skills/ae-analysis/references/system_query_task_get.md +2 -0
- package/skills/ae-analysis/references/system_query_task_list.md +7 -3
- package/skills/ae-analysis/references/system_query_task_options.md +2 -2
- package/skills/ae-analysis/references/system_query_task_realtime_list.md +15 -0
- package/skills/ae-analysis/references/user_cluster_models.md +8 -0
- package/skills/ae-analysis/references/user_tag_create.md +7 -1
- package/skills/ae-analysis/references/user_tag_get.md +1 -1
- package/skills/ae-analysis/references/user_tag_models.md +20 -2
- package/skills/ae-analysis/references/user_tag_refresh.md +1 -1
- package/skills/ae-analysis/references/user_tag_update.md +2 -2
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-empty-skeleton.mjs +105 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +669 -29
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +21 -8
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +28 -10
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +66 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +285 -24
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +262 -30
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/plan-kb-source-sync.mjs +1 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/precompiled-source.mjs +46 -2
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/prepare-compile-schema.mjs +64 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/refresh-state-parts.mjs +91 -0
- package/skills/ae-automation/SKILL.md +16 -0
- package/skills/ae-automation/references/cli.md +53 -0
- package/skills/ae-automation/references/command_index.md +17 -0
- package/skills/ae-capability/SKILL.md +73 -2
- package/skills/ae-capability/references/collaboration.md +48 -0
- package/skills/ae-community/SKILL.md +5 -1
- package/skills/ae-community/references/collaboration.md +48 -0
- package/skills/ae-current-context/SKILL.md +3 -2
- package/skills/ae-data-integration/SKILL.md +4 -0
- package/skills/ae-data-integration/references/collaboration.md +48 -0
- package/skills/ae-dataops/SKILL.md +54 -74
- package/skills/ae-dataops/references/collaboration.md +48 -0
- package/skills/ae-dataops/references/dataops-backfill.md +23 -18
- package/skills/ae-dataops/references/dataops-flow-create.md +74 -23
- package/skills/ae-dataops/references/dataops-flow-monitor.md +45 -13
- package/skills/ae-dataops/references/dataops-integration.md +57 -30
- package/skills/ae-dataops/references/dataops-query.md +21 -4
- package/skills/ae-dataops/references/dataops-table.md +143 -11
- package/skills/ae-engage/SKILL.md +21 -6
- package/skills/ae-engage/references/channel-mgmt.md +3 -3
- package/skills/ae-engage/references/collaboration.md +48 -0
- package/skills/ae-engage/references/scene-config-channel.md +4 -4
- package/skills/ae-generate-tracking-plan/SKILL.md +4 -0
- package/skills/ae-generate-tracking-plan/references/collaboration.md +48 -0
- package/skills/ae-kb/SKILL.md +70 -12
- package/skills/ae-kb/references/analysis-workflow.md +73 -36
- package/skills/ae-kb/references/collaboration.md +48 -0
- package/skills/ae-kb/references/query-workflow.md +67 -33
- package/skills/ae-kb/references/schema-import.md +32 -0
- package/skills/ae-kb/references/source-mutations.md +6 -4
- package/skills/ae-kb/references/text-sources.md +53 -0
- package/skills/ae-kb-discovery/SKILL.md +8 -3
- package/skills/ae-kb-discovery/references/collaboration.md +48 -0
- package/skills/ae-metadata/SKILL.md +20 -12
- package/skills/ae-metadata/references/collaboration.md +48 -0
- package/skills/ae-team/SKILL.md +23 -17
- package/skills/ae-things/SKILL.md +85 -0
- package/skills/ae-things/references/cli.md +103 -0
- package/skills/ae-things-progress/SKILL.md +43 -0
- package/skills/ae-things-review/SKILL.md +42 -0
- package/skills/ae-workspace/SKILL.md +43 -0
- package/skills/ae-workspace/references/commands.md +51 -0
- package/dist/chunk-E2JKXMVO.js +0 -29
- package/dist/context-IFJI3LIT.js +0 -46
- package/dist/memory-QGPSNCQS.js +0 -892
- package/skills/ae-agent/references/create-automation.md +0 -125
- package/skills/ae-agent/references/list-automations.md +0 -56
- package/skills/ae-agent/references/update-automation.md +0 -107
|
@@ -0,0 +1,1091 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
resolveMemoryApiBaseUrl
|
|
4
|
+
} from "./chunk-D6ACFILC.js";
|
|
5
|
+
import "./chunk-4655PUNX.js";
|
|
6
|
+
import "./chunk-PLE722AJ.js";
|
|
7
|
+
import {
|
|
8
|
+
CapabilityGatewayError,
|
|
9
|
+
buildCapabilityGatewayUrl,
|
|
10
|
+
callCapabilityApi
|
|
11
|
+
} from "./chunk-EOYSKMXN.js";
|
|
12
|
+
import "./chunk-Y74WTIKJ.js";
|
|
13
|
+
import "./chunk-GIK6EDUG.js";
|
|
14
|
+
import "./chunk-UQ77JXYH.js";
|
|
15
|
+
import {
|
|
16
|
+
PermissionError
|
|
17
|
+
} from "./chunk-WNGFSIOB.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/things/parity-actions.ts
|
|
20
|
+
import { readFileSync } from "fs";
|
|
21
|
+
var stringFlag = (name, desc, required = false) => ({
|
|
22
|
+
name,
|
|
23
|
+
type: "string",
|
|
24
|
+
desc,
|
|
25
|
+
required
|
|
26
|
+
});
|
|
27
|
+
var conversationFlag = stringFlag(
|
|
28
|
+
"conversation-id",
|
|
29
|
+
"Owned conversation ID",
|
|
30
|
+
true
|
|
31
|
+
);
|
|
32
|
+
var contentFlags = [
|
|
33
|
+
{ ...stringFlag("content", "Text content"), sensitive: true },
|
|
34
|
+
{ ...stringFlag("file", "UTF-8 text file"), sensitive: true },
|
|
35
|
+
{ name: "stdin", type: "boolean", desc: "Read text from stdin" }
|
|
36
|
+
];
|
|
37
|
+
function content(ctx) {
|
|
38
|
+
if ([
|
|
39
|
+
Boolean(ctx.str("content")),
|
|
40
|
+
Boolean(ctx.str("file")),
|
|
41
|
+
ctx.bool("stdin")
|
|
42
|
+
].filter(Boolean).length !== 1)
|
|
43
|
+
throw new Error("Specify exactly one of --content, --file or --stdin");
|
|
44
|
+
if (ctx.bool("stdin") && process.stdin.isTTY)
|
|
45
|
+
throw new Error("Pipe text to --stdin");
|
|
46
|
+
return ctx.str("content") || readFileSync(ctx.str("file") || 0, "utf8");
|
|
47
|
+
}
|
|
48
|
+
function parityActions(id, pageFlags2, pageQuery2) {
|
|
49
|
+
const thingFlag = stringFlag("id", "Thing ID", true);
|
|
50
|
+
const conversationPath = (ctx) => `/things/conversation/${id(ctx.str("conversationId"))}`;
|
|
51
|
+
return [
|
|
52
|
+
...["members", "options"].map((command) => ({
|
|
53
|
+
command,
|
|
54
|
+
method: "GET",
|
|
55
|
+
suffix: () => `/things/${command}`,
|
|
56
|
+
flags: [
|
|
57
|
+
...pageFlags2,
|
|
58
|
+
...command === "options" ? [stringFlag("query", "Search candidates")] : []
|
|
59
|
+
],
|
|
60
|
+
params: (ctx) => ({
|
|
61
|
+
...pageQuery2(ctx),
|
|
62
|
+
...command === "options" && ctx.str("query") ? { query: ctx.str("query") } : {}
|
|
63
|
+
})
|
|
64
|
+
})),
|
|
65
|
+
...["add", "remove"].map((command) => ({
|
|
66
|
+
resource: "collaborator",
|
|
67
|
+
command,
|
|
68
|
+
method: command === "remove" ? "DELETE" : "POST",
|
|
69
|
+
suffix: (ctx) => `/things/${id(ctx.str("id"))}/collaborators`,
|
|
70
|
+
flags: [thingFlag, stringFlag("user-id", "Space member ID", true)],
|
|
71
|
+
body: (ctx) => ({ userId: id(ctx.str("userId")) })
|
|
72
|
+
})),
|
|
73
|
+
{
|
|
74
|
+
resource: "entry",
|
|
75
|
+
command: "update",
|
|
76
|
+
method: "PATCH",
|
|
77
|
+
suffix: (ctx) => `/things/${id(ctx.str("id"))}/entries/${id(ctx.str("entryId"))}`,
|
|
78
|
+
flags: [
|
|
79
|
+
thingFlag,
|
|
80
|
+
stringFlag("entry-id", "Entry ID", true),
|
|
81
|
+
stringFlag(
|
|
82
|
+
"expected-updated-at",
|
|
83
|
+
"Timestamp from the latest entry read",
|
|
84
|
+
true
|
|
85
|
+
),
|
|
86
|
+
...contentFlags,
|
|
87
|
+
{ ...stringFlag("title", "Entry title"), sensitive: true },
|
|
88
|
+
{ name: "clear-title", type: "boolean", desc: "Clear the entry title" },
|
|
89
|
+
stringFlag("type", "note | url | progress")
|
|
90
|
+
],
|
|
91
|
+
validate: (ctx) => {
|
|
92
|
+
if (ctx.str("title") && ctx.bool("clearTitle"))
|
|
93
|
+
throw new Error("Use --title or --clear-title");
|
|
94
|
+
if (ctx.str("type") && !["note", "url", "progress"].includes(ctx.str("type")))
|
|
95
|
+
throw new Error("Entry type must be note, url or progress");
|
|
96
|
+
if (ctx.str("title") && !ctx.str("title").trim())
|
|
97
|
+
throw new Error("Entry title must not be blank");
|
|
98
|
+
if (ctx.str("title").trim().length > 200)
|
|
99
|
+
throw new Error("Entry title exceeds 200 characters");
|
|
100
|
+
if (!["content", "file", "title", "type"].some((key) => ctx.str(key)) && !ctx.bool("stdin") && !ctx.bool("clearTitle"))
|
|
101
|
+
throw new Error("Provide at least one entry field to update");
|
|
102
|
+
},
|
|
103
|
+
body: (ctx) => ({
|
|
104
|
+
...ctx.str("content") || ctx.str("file") || ctx.bool("stdin") ? { content: content(ctx) } : {},
|
|
105
|
+
...ctx.bool("clearTitle") ? { title: null } : ctx.str("title") ? { title: ctx.str("title") } : {},
|
|
106
|
+
...ctx.str("type") ? { type: ctx.str("type") } : {},
|
|
107
|
+
expectedUpdatedAt: ctx.str("expectedUpdatedAt")
|
|
108
|
+
})
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
resource: "conversation",
|
|
112
|
+
command: "get",
|
|
113
|
+
method: "GET",
|
|
114
|
+
suffix: (ctx) => `${conversationPath(ctx)}/snapshot`,
|
|
115
|
+
flags: [conversationFlag]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
resource: "conversation",
|
|
119
|
+
command: "primary",
|
|
120
|
+
method: "GET",
|
|
121
|
+
suffix: conversationPath,
|
|
122
|
+
flags: [conversationFlag]
|
|
123
|
+
},
|
|
124
|
+
...["bind", "unbind"].map((command) => ({
|
|
125
|
+
resource: "conversation",
|
|
126
|
+
command,
|
|
127
|
+
method: "POST",
|
|
128
|
+
suffix: conversationPath,
|
|
129
|
+
risk: command === "unbind" ? "high-risk-write" : "write",
|
|
130
|
+
flags: [conversationFlag, ...command === "bind" ? [thingFlag] : []],
|
|
131
|
+
body: (ctx) => ({
|
|
132
|
+
primaryThingId: command === "bind" ? id(ctx.str("id")) : null
|
|
133
|
+
})
|
|
134
|
+
})),
|
|
135
|
+
{
|
|
136
|
+
command: "from-message",
|
|
137
|
+
method: "POST",
|
|
138
|
+
suffix: () => "/things/from-message",
|
|
139
|
+
flags: [
|
|
140
|
+
conversationFlag,
|
|
141
|
+
stringFlag("message-id", "Source message ID", true),
|
|
142
|
+
...contentFlags,
|
|
143
|
+
stringFlag("id", "Existing thing ID; omit to create from --title"),
|
|
144
|
+
{ ...stringFlag("title", "New thing title"), sensitive: true },
|
|
145
|
+
stringFlag(
|
|
146
|
+
"entry-type",
|
|
147
|
+
"note | progress; only with --id (default: note)"
|
|
148
|
+
)
|
|
149
|
+
],
|
|
150
|
+
validate: (ctx) => {
|
|
151
|
+
if (Boolean(ctx.str("id")) === Boolean(ctx.str("title")))
|
|
152
|
+
throw new Error("Specify either --id or --title");
|
|
153
|
+
if (ctx.str("title") && ctx.str("entryType"))
|
|
154
|
+
throw new Error(
|
|
155
|
+
"--entry-type is only supported with --id, not --title"
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
body: (ctx) => {
|
|
159
|
+
return {
|
|
160
|
+
conversationId: id(ctx.str("conversationId")),
|
|
161
|
+
messageId: id(ctx.str("messageId")),
|
|
162
|
+
content: content(ctx),
|
|
163
|
+
...ctx.str("entryType") ? { entryType: ctx.str("entryType") } : {},
|
|
164
|
+
...ctx.str("id") ? { thingId: id(ctx.str("id")) } : { fields: { title: ctx.str("title") } }
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/commands/things/client.ts
|
|
172
|
+
function thingsUrl(ctx, path) {
|
|
173
|
+
return buildCapabilityGatewayUrl(
|
|
174
|
+
resolveMemoryApiBaseUrl(ctx.host()),
|
|
175
|
+
"things",
|
|
176
|
+
path,
|
|
177
|
+
{},
|
|
178
|
+
"v1"
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
async function requestThings(ctx, method, path, body) {
|
|
182
|
+
try {
|
|
183
|
+
return await callCapabilityApi(ctx.host(), "things", path, method, body, {
|
|
184
|
+
apiBaseUrl: resolveMemoryApiBaseUrl(ctx.host()),
|
|
185
|
+
apiVersion: "v1",
|
|
186
|
+
includeClientContextInBody: false,
|
|
187
|
+
retryOnInvalidTokenForbidden: false
|
|
188
|
+
});
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (error instanceof PermissionError)
|
|
191
|
+
throw new PermissionError(
|
|
192
|
+
"You cannot access this workspace thing.",
|
|
193
|
+
error.code
|
|
194
|
+
);
|
|
195
|
+
if (error instanceof CapabilityGatewayError) {
|
|
196
|
+
const messages = {
|
|
197
|
+
THING_VERSION_CONFLICT: "The thing changed. Read it again and submit the current expected version.",
|
|
198
|
+
THING_TARGET_CONFLICT: "The requested target conflicts with the conversation or execution.",
|
|
199
|
+
THING_CONTEXT_UNAVAILABLE: "The execution snapshot is missing or invalid. Start a new execution; do not fall back to live context.",
|
|
200
|
+
THING_ASSET_UNAVAILABLE: "A referenced file is missing or cannot be verified. Restore it or update the thing references.",
|
|
201
|
+
THING_TARGET_REQUIRED: "Specify --agent-space-id or run inside a Web Agent conversation.",
|
|
202
|
+
THING_NOT_FOUND: "The thing does not exist or is not accessible in this space.",
|
|
203
|
+
THING_READ_ONLY: "The requested resource is read-only and cannot be modified.",
|
|
204
|
+
THING_COMMAND_CONFLICT: "The command ID was already used with different input.",
|
|
205
|
+
THING_INVALID_INPUT: "Invalid thing input. Check identifiers, fields and limits."
|
|
206
|
+
};
|
|
207
|
+
throw new CapabilityGatewayError(
|
|
208
|
+
messages[error.code ?? ""] ?? "Workspace thing request failed. Inspect the error code.",
|
|
209
|
+
error.code,
|
|
210
|
+
error.httpStatus
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/commands/things/collect.ts
|
|
218
|
+
async function collectThingsPages(fetchPage, maximum = 1e4) {
|
|
219
|
+
const items = [];
|
|
220
|
+
const ids = /* @__PURE__ */ new Set();
|
|
221
|
+
const cursors = /* @__PURE__ */ new Set();
|
|
222
|
+
let cursor;
|
|
223
|
+
for (let pageIndex = 0; pageIndex < 100; pageIndex++) {
|
|
224
|
+
let page;
|
|
225
|
+
try {
|
|
226
|
+
page = await fetchPage(cursor);
|
|
227
|
+
} catch {
|
|
228
|
+
return {
|
|
229
|
+
items,
|
|
230
|
+
fetchedCount: items.length,
|
|
231
|
+
truncated: true,
|
|
232
|
+
collectionError: "PAGE_REQUEST_FAILED"
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (!page || !Array.isArray(page.items) || !(page.nextCursor === null || typeof page.nextCursor === "string"))
|
|
236
|
+
return {
|
|
237
|
+
items,
|
|
238
|
+
fetchedCount: items.length,
|
|
239
|
+
truncated: true,
|
|
240
|
+
collectionError: "INVALID_PAGE"
|
|
241
|
+
};
|
|
242
|
+
for (const item of page.items) {
|
|
243
|
+
if (!item || typeof item.id !== "string" || ids.has(item.id))
|
|
244
|
+
return {
|
|
245
|
+
items,
|
|
246
|
+
fetchedCount: items.length,
|
|
247
|
+
truncated: true,
|
|
248
|
+
collectionError: "DUPLICATE_OR_INVALID_ITEM"
|
|
249
|
+
};
|
|
250
|
+
if (items.length >= maximum)
|
|
251
|
+
return {
|
|
252
|
+
items,
|
|
253
|
+
fetchedCount: items.length,
|
|
254
|
+
truncated: true,
|
|
255
|
+
collectionError: "COLLECTION_LIMIT"
|
|
256
|
+
};
|
|
257
|
+
ids.add(item.id);
|
|
258
|
+
items.push(item);
|
|
259
|
+
}
|
|
260
|
+
if (!page.nextCursor)
|
|
261
|
+
return {
|
|
262
|
+
items,
|
|
263
|
+
fetchedCount: items.length,
|
|
264
|
+
truncated: false,
|
|
265
|
+
collectionError: null
|
|
266
|
+
};
|
|
267
|
+
if (cursors.has(page.nextCursor) || !page.items.length)
|
|
268
|
+
return {
|
|
269
|
+
items,
|
|
270
|
+
fetchedCount: items.length,
|
|
271
|
+
truncated: true,
|
|
272
|
+
collectionError: "CURSOR_DID_NOT_ADVANCE"
|
|
273
|
+
};
|
|
274
|
+
cursors.add(page.nextCursor);
|
|
275
|
+
cursor = page.nextCursor;
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
items,
|
|
279
|
+
fetchedCount: items.length,
|
|
280
|
+
truncated: true,
|
|
281
|
+
collectionError: "COLLECTION_LIMIT"
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function thingsWindow(ctx) {
|
|
285
|
+
const start = ctx.str("from");
|
|
286
|
+
const end = ctx.str("to");
|
|
287
|
+
const timeZone = ctx.str("timeZone") || "Asia/Shanghai";
|
|
288
|
+
try {
|
|
289
|
+
new Intl.DateTimeFormat("en", { timeZone });
|
|
290
|
+
} catch {
|
|
291
|
+
throw new Error("Invalid --time-zone");
|
|
292
|
+
}
|
|
293
|
+
if (Boolean(start) !== Boolean(end))
|
|
294
|
+
throw new Error("Specify both --from and --to with explicit timezones");
|
|
295
|
+
for (const value of [start, end].filter(Boolean))
|
|
296
|
+
if (!/T.*(?:Z|[+-]\d{2}:\d{2})$/.test(value) || !Number.isFinite(Date.parse(value)))
|
|
297
|
+
throw new Error("Use ISO timestamps with explicit timezone offsets");
|
|
298
|
+
if (start && Date.parse(start) >= Date.parse(end))
|
|
299
|
+
throw new Error("--from must be earlier than --to");
|
|
300
|
+
return {
|
|
301
|
+
start: start ? new Date(start).toISOString() : null,
|
|
302
|
+
end: end ? new Date(end).toISOString() : null,
|
|
303
|
+
timeZone
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function factsInWindow(thing, entries, start, end) {
|
|
307
|
+
const effective = (entry) => entry.type === "progress";
|
|
308
|
+
const startMs = start ? Date.parse(start) : -Infinity;
|
|
309
|
+
const endMs = end ? Date.parse(end) : Infinity;
|
|
310
|
+
const ordered = [...entries].sort(
|
|
311
|
+
(a, b) => Date.parse(String(b.createdAt)) - Date.parse(String(a.createdAt)) || (String(a.id) < String(b.id) ? 1 : String(a.id) > String(b.id) ? -1 : 0)
|
|
312
|
+
);
|
|
313
|
+
const inWindow = ordered.filter(
|
|
314
|
+
(e) => Date.parse(String(e.createdAt)) >= startMs && Date.parse(String(e.createdAt)) < endMs
|
|
315
|
+
);
|
|
316
|
+
const baseline = Object.fromEntries(
|
|
317
|
+
["status", "assigneeId", "tags"].map((key) => [key, thing[key]])
|
|
318
|
+
);
|
|
319
|
+
baseline.archived = Boolean(thing.archivedAt);
|
|
320
|
+
for (const entry of ordered) {
|
|
321
|
+
if (Date.parse(String(entry.createdAt)) < startMs) continue;
|
|
322
|
+
if (entry.type === "updated" && entry.dataJson && typeof entry.dataJson === "object")
|
|
323
|
+
for (const [key, change] of Object.entries(entry.dataJson)) {
|
|
324
|
+
if (key in baseline && change && typeof change === "object" && "before" in change)
|
|
325
|
+
baseline[key] = change.before;
|
|
326
|
+
}
|
|
327
|
+
if (entry.type === "status" && entry.dataJson && typeof entry.dataJson === "object" && "before" in entry.dataJson) {
|
|
328
|
+
baseline.status = entry.dataJson.before;
|
|
329
|
+
baseline.archived = entry.dataJson.before === "archived";
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
baseline: !start || Date.parse(String(thing.createdAt)) >= startMs ? null : baseline,
|
|
334
|
+
entries: inWindow,
|
|
335
|
+
effectiveProgressCount: inWindow.filter((e) => effective(e)).length,
|
|
336
|
+
lastEffectiveRecordBeforeWindow: ordered.find(
|
|
337
|
+
(e) => effective(e) && Date.parse(String(e.createdAt)) < startMs
|
|
338
|
+
) ?? null
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async function collectThingDetail(ctx, root2, id) {
|
|
342
|
+
const thing = await requestThings(ctx, "GET", `${root2}/things/${id}`);
|
|
343
|
+
const entries = await collectThingsPages(
|
|
344
|
+
(cursor) => requestThings(
|
|
345
|
+
ctx,
|
|
346
|
+
"GET",
|
|
347
|
+
`${root2}/things/${id}/entries?limit=100${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}`
|
|
348
|
+
)
|
|
349
|
+
);
|
|
350
|
+
const assets = await collectThingsPages(
|
|
351
|
+
(cursor) => requestThings(
|
|
352
|
+
ctx,
|
|
353
|
+
"GET",
|
|
354
|
+
`${root2}/things/${id}/assets?limit=100${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}`
|
|
355
|
+
)
|
|
356
|
+
);
|
|
357
|
+
const context = await requestThings(
|
|
358
|
+
ctx,
|
|
359
|
+
"GET",
|
|
360
|
+
`${root2}/things/${id}/context`
|
|
361
|
+
);
|
|
362
|
+
return {
|
|
363
|
+
thing,
|
|
364
|
+
entries: entries.items,
|
|
365
|
+
context,
|
|
366
|
+
assets: assets.items,
|
|
367
|
+
fetchedCount: 1 + entries.fetchedCount + assets.fetchedCount,
|
|
368
|
+
truncated: entries.truncated || assets.truncated,
|
|
369
|
+
collectionErrors: [entries.collectionError, assets.collectionError].filter(
|
|
370
|
+
Boolean
|
|
371
|
+
),
|
|
372
|
+
consistency: context.thing.version === thing.version ? "non_transactional" : "changed_during_collection",
|
|
373
|
+
collectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
async function collectThingDigest(ctx, root2, explicitIds2) {
|
|
377
|
+
const window = thingsWindow(ctx);
|
|
378
|
+
const params = new URLSearchParams({ limit: "100" });
|
|
379
|
+
if (ctx.str("assigneeId")) params.set("assigneeId", ctx.str("assigneeId"));
|
|
380
|
+
const listing = explicitIds2.length ? {
|
|
381
|
+
items: explicitIds2.map((id) => ({ id })),
|
|
382
|
+
truncated: false,
|
|
383
|
+
collectionError: null
|
|
384
|
+
} : await (async () => {
|
|
385
|
+
const pages = await Promise.all(
|
|
386
|
+
["", "archived"].map(
|
|
387
|
+
(status) => collectThingsPages(
|
|
388
|
+
(cursor) => requestThings(
|
|
389
|
+
ctx,
|
|
390
|
+
"GET",
|
|
391
|
+
`${root2}/things?${params}${status ? `&status=${status}` : ""}${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}`
|
|
392
|
+
)
|
|
393
|
+
)
|
|
394
|
+
)
|
|
395
|
+
);
|
|
396
|
+
return {
|
|
397
|
+
items: [
|
|
398
|
+
...new Map(
|
|
399
|
+
pages.flatMap((page) => page.items).map((item) => [item.id, item])
|
|
400
|
+
).values()
|
|
401
|
+
],
|
|
402
|
+
truncated: pages.some((page) => page.truncated),
|
|
403
|
+
collectionError: pages.find((page) => page.collectionError)?.collectionError ?? null
|
|
404
|
+
};
|
|
405
|
+
})();
|
|
406
|
+
const items = [];
|
|
407
|
+
const unreadable = [];
|
|
408
|
+
for (const item of listing.items) {
|
|
409
|
+
try {
|
|
410
|
+
const detail = await collectThingDetail(ctx, root2, item.id);
|
|
411
|
+
const facts = factsInWindow(
|
|
412
|
+
detail.thing,
|
|
413
|
+
detail.entries,
|
|
414
|
+
window.start,
|
|
415
|
+
window.end
|
|
416
|
+
);
|
|
417
|
+
items.push({
|
|
418
|
+
...detail,
|
|
419
|
+
...facts,
|
|
420
|
+
baseline: detail.truncated || detail.consistency === "changed_during_collection" ? null : facts.baseline
|
|
421
|
+
});
|
|
422
|
+
} catch {
|
|
423
|
+
unreadable.push({ id: item.id, code: "ITEM_UNREADABLE" });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const statuses = ["open", "paused", "done"];
|
|
427
|
+
const counts = Object.fromEntries(
|
|
428
|
+
statuses.map((status) => [
|
|
429
|
+
status,
|
|
430
|
+
items.filter((i) => !i.thing.archivedAt && i.thing.status === status).length
|
|
431
|
+
])
|
|
432
|
+
);
|
|
433
|
+
return {
|
|
434
|
+
items,
|
|
435
|
+
counts,
|
|
436
|
+
archivedCount: items.filter((i) => Boolean(i.thing.archivedAt)).length,
|
|
437
|
+
...explicitIds2.length ? { requestedCount: explicitIds2.length, unreadable } : { unreadableCount: unreadable.length },
|
|
438
|
+
fetchedCount: items.length,
|
|
439
|
+
truncated: listing.truncated || unreadable.length > 0 || items.some((i) => i.truncated),
|
|
440
|
+
collectionError: listing.collectionError,
|
|
441
|
+
consistency: items.some(
|
|
442
|
+
(i) => i.consistency === "changed_during_collection"
|
|
443
|
+
) ? "changed_during_collection" : "non_transactional",
|
|
444
|
+
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
445
|
+
window
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/commands/things/index.ts
|
|
450
|
+
import { randomUUID } from "crypto";
|
|
451
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
452
|
+
var targetFlags = [
|
|
453
|
+
{
|
|
454
|
+
name: "agent-space-id",
|
|
455
|
+
type: "string",
|
|
456
|
+
desc: "Explicit space; must match the current conversation"
|
|
457
|
+
}
|
|
458
|
+
];
|
|
459
|
+
var idFlag = {
|
|
460
|
+
name: "id",
|
|
461
|
+
type: "string",
|
|
462
|
+
required: true,
|
|
463
|
+
desc: "Resource ID returned by the API"
|
|
464
|
+
};
|
|
465
|
+
var commandFlag = {
|
|
466
|
+
name: "command-id",
|
|
467
|
+
type: "string",
|
|
468
|
+
desc: "Stable UUID for safe retries; generated when omitted"
|
|
469
|
+
};
|
|
470
|
+
var versionFlag = {
|
|
471
|
+
name: "expected-version",
|
|
472
|
+
type: "number",
|
|
473
|
+
required: true,
|
|
474
|
+
min: 1,
|
|
475
|
+
desc: "Version read before this edit"
|
|
476
|
+
};
|
|
477
|
+
var pageFlags = [
|
|
478
|
+
{
|
|
479
|
+
name: "limit",
|
|
480
|
+
type: "number",
|
|
481
|
+
min: 1,
|
|
482
|
+
max: 100,
|
|
483
|
+
desc: "Page size, at most 100"
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
name: "cursor",
|
|
487
|
+
type: "string",
|
|
488
|
+
desc: "Opaque cursor from the previous response"
|
|
489
|
+
}
|
|
490
|
+
];
|
|
491
|
+
var thingFlags = [
|
|
492
|
+
{
|
|
493
|
+
name: "title",
|
|
494
|
+
type: "string",
|
|
495
|
+
sensitive: true,
|
|
496
|
+
desc: "Thing title, 1 to 200 characters"
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
name: "description",
|
|
500
|
+
type: "string",
|
|
501
|
+
sensitive: true,
|
|
502
|
+
desc: "Required when creating; at most 10000 characters"
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
name: "tags",
|
|
506
|
+
type: "string",
|
|
507
|
+
sensitive: true,
|
|
508
|
+
desc: "JSON array of tags; [] clears tags"
|
|
509
|
+
},
|
|
510
|
+
{ name: "status", type: "string", desc: "open | paused | done" },
|
|
511
|
+
{
|
|
512
|
+
name: "assignee-id",
|
|
513
|
+
type: "string",
|
|
514
|
+
desc: "Active member ID; creation defaults to self; null is rejected"
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
name: "collaborator-ids",
|
|
518
|
+
type: "string",
|
|
519
|
+
desc: "JSON array of member IDs; [] clears collaborators"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
name: "file",
|
|
523
|
+
type: "string",
|
|
524
|
+
sensitive: true,
|
|
525
|
+
desc: "UTF-8 JSON file containing thing fields"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
name: "stdin",
|
|
529
|
+
type: "boolean",
|
|
530
|
+
desc: "Read thing field JSON from standard input"
|
|
531
|
+
}
|
|
532
|
+
];
|
|
533
|
+
function validThingsId(value) {
|
|
534
|
+
if (!/^[A-Za-z0-9_-]{1,191}$/.test(value))
|
|
535
|
+
throw new Error("Invalid resource identifier");
|
|
536
|
+
return value;
|
|
537
|
+
}
|
|
538
|
+
function thingsTarget(ctx) {
|
|
539
|
+
const agentSpaceId = ctx.str("agentSpaceId").trim();
|
|
540
|
+
const conversationId = process.env.TE_AGENT_CONVERSATION_ID?.trim();
|
|
541
|
+
if (!agentSpaceId && !conversationId)
|
|
542
|
+
throw new Error(
|
|
543
|
+
"Specify --agent-space-id or run inside a Web Agent conversation"
|
|
544
|
+
);
|
|
545
|
+
return {
|
|
546
|
+
...agentSpaceId ? { agentSpaceId: validThingsId(agentSpaceId) } : {},
|
|
547
|
+
...conversationId ? { conversationId: validThingsId(conversationId) } : {}
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function query(values) {
|
|
551
|
+
const q = new URLSearchParams();
|
|
552
|
+
for (const [key, value] of Object.entries(values))
|
|
553
|
+
if (value !== void 0) q.set(key, String(value));
|
|
554
|
+
return q.size ? `?${q}` : "";
|
|
555
|
+
}
|
|
556
|
+
async function root(ctx) {
|
|
557
|
+
const selected = thingsTarget(ctx);
|
|
558
|
+
const resolved = await requestThings(
|
|
559
|
+
ctx,
|
|
560
|
+
"GET",
|
|
561
|
+
`target${query(selected)}`
|
|
562
|
+
);
|
|
563
|
+
const id = validThingsId(resolved.agentSpaceId);
|
|
564
|
+
if (selected.agentSpaceId && selected.agentSpaceId !== id)
|
|
565
|
+
throw new Error("Server resolved a conflicting space");
|
|
566
|
+
return `agent-spaces/${id}`;
|
|
567
|
+
}
|
|
568
|
+
function pageQuery(ctx) {
|
|
569
|
+
const limit = ctx.optionalNum("limit") ?? 50;
|
|
570
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
571
|
+
throw new Error("--limit must be between 1 and 100");
|
|
572
|
+
return { limit, ...ctx.str("cursor") ? { cursor: ctx.str("cursor") } : {} };
|
|
573
|
+
}
|
|
574
|
+
function thingBody(ctx) {
|
|
575
|
+
if (ctx.str("file") && ctx.bool("stdin"))
|
|
576
|
+
throw new Error("Use either --file or --stdin");
|
|
577
|
+
if (ctx.bool("stdin") && process.stdin.isTTY)
|
|
578
|
+
throw new Error("Pipe JSON to --stdin");
|
|
579
|
+
const input = ctx.str("file") ? readFileSync2(ctx.str("file"), "utf8") : ctx.bool("stdin") ? readFileSync2(0, "utf8") : "";
|
|
580
|
+
let fields;
|
|
581
|
+
try {
|
|
582
|
+
fields = input ? JSON.parse(input) : {};
|
|
583
|
+
} catch {
|
|
584
|
+
throw new Error("Invalid thing JSON. Supply a valid JSON object.");
|
|
585
|
+
}
|
|
586
|
+
if (!fields || Array.isArray(fields) || typeof fields !== "object")
|
|
587
|
+
throw new Error("Input must be an thing field object");
|
|
588
|
+
const allowed = [
|
|
589
|
+
"title",
|
|
590
|
+
"description",
|
|
591
|
+
"tags",
|
|
592
|
+
"status",
|
|
593
|
+
"assigneeId",
|
|
594
|
+
"collaboratorIds"
|
|
595
|
+
];
|
|
596
|
+
if (Object.keys(fields).some((key) => !allowed.includes(key)))
|
|
597
|
+
throw new Error("Input contains unsupported thing fields");
|
|
598
|
+
for (const key of allowed) {
|
|
599
|
+
const value = ctx.str(key);
|
|
600
|
+
if (value) {
|
|
601
|
+
if (["tags", "collaboratorIds"].includes(key)) {
|
|
602
|
+
try {
|
|
603
|
+
fields[key] = JSON.parse(value);
|
|
604
|
+
} catch {
|
|
605
|
+
throw new Error(`--${key} requires a JSON string array`);
|
|
606
|
+
}
|
|
607
|
+
} else fields[key] = value;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
if (fields.assigneeId !== void 0 && (fields.assigneeId === null || fields.assigneeId === "null" || typeof fields.assigneeId !== "string" || !fields.assigneeId.trim()))
|
|
611
|
+
throw new Error(
|
|
612
|
+
"Assignee must be an active member ID; null is not allowed"
|
|
613
|
+
);
|
|
614
|
+
for (const key of ["tags", "collaboratorIds"]) {
|
|
615
|
+
if (fields[key] !== void 0 && (!Array.isArray(fields[key]) || !fields[key].every((value) => typeof value === "string")))
|
|
616
|
+
throw new Error(`${key} must be a string array`);
|
|
617
|
+
}
|
|
618
|
+
if (fields.status && !["open", "paused", "done"].includes(String(fields.status)))
|
|
619
|
+
throw new Error("Invalid thing status");
|
|
620
|
+
return fields;
|
|
621
|
+
}
|
|
622
|
+
var validateAttachmentRole = (ctx) => {
|
|
623
|
+
if (ctx.str("role") && ctx.str("role") !== "attachment")
|
|
624
|
+
throw new Error("--role only accepts attachment");
|
|
625
|
+
};
|
|
626
|
+
var thingId = (ctx) => validThingsId(ctx.str("id"));
|
|
627
|
+
function sourceBody(ctx) {
|
|
628
|
+
if (ctx.str("conversationId") && process.env.TE_AGENT_CONVERSATION_ID && ctx.str("conversationId") !== process.env.TE_AGENT_CONVERSATION_ID)
|
|
629
|
+
throw new Error(
|
|
630
|
+
"Source conversation must match the current execution conversation"
|
|
631
|
+
);
|
|
632
|
+
const conversationId = ctx.str("conversationId") || process.env.TE_AGENT_CONVERSATION_ID;
|
|
633
|
+
return {
|
|
634
|
+
...conversationId ? { conversationId: validThingsId(conversationId) } : {},
|
|
635
|
+
...ctx.str("runId") ? { runId: validThingsId(ctx.str("runId")) } : {}
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
var actions = [
|
|
639
|
+
...parityActions(validThingsId, pageFlags, pageQuery),
|
|
640
|
+
{
|
|
641
|
+
resource: "asset",
|
|
642
|
+
command: "available",
|
|
643
|
+
method: "GET",
|
|
644
|
+
suffix: () => "/things/assets",
|
|
645
|
+
flags: [...pageFlags],
|
|
646
|
+
params: pageQuery
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
resource: "asset",
|
|
650
|
+
command: "list",
|
|
651
|
+
method: "GET",
|
|
652
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/assets`,
|
|
653
|
+
flags: [idFlag, ...pageFlags],
|
|
654
|
+
params: pageQuery
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
resource: "asset",
|
|
658
|
+
command: "link",
|
|
659
|
+
validate: (ctx) => {
|
|
660
|
+
validateAttachmentRole(ctx);
|
|
661
|
+
if (Boolean(ctx.str("assetId")) === Boolean(ctx.str("path")))
|
|
662
|
+
throw new Error("Specify exactly one of --asset-id or --path");
|
|
663
|
+
},
|
|
664
|
+
method: "POST",
|
|
665
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/assets`,
|
|
666
|
+
flags: [
|
|
667
|
+
idFlag,
|
|
668
|
+
{
|
|
669
|
+
name: "asset-id",
|
|
670
|
+
type: "string",
|
|
671
|
+
desc: "Stable space asset ID"
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
name: "path",
|
|
675
|
+
type: "string",
|
|
676
|
+
sensitive: true,
|
|
677
|
+
desc: "Space-relative file path returned by asset available"
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
name: "role",
|
|
681
|
+
type: "string",
|
|
682
|
+
desc: "attachment (default; only supported role)"
|
|
683
|
+
}
|
|
684
|
+
],
|
|
685
|
+
body: (ctx) => ({
|
|
686
|
+
...ctx.str("assetId") ? { assetId: validThingsId(ctx.str("assetId")) } : { path: ctx.str("path") },
|
|
687
|
+
role: ctx.str("role") || "attachment"
|
|
688
|
+
})
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
resource: "asset",
|
|
692
|
+
command: "unlink",
|
|
693
|
+
method: "DELETE",
|
|
694
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/assets`,
|
|
695
|
+
flags: [
|
|
696
|
+
idFlag,
|
|
697
|
+
{
|
|
698
|
+
name: "asset-id",
|
|
699
|
+
type: "string",
|
|
700
|
+
required: true,
|
|
701
|
+
desc: "Stable space asset ID"
|
|
702
|
+
}
|
|
703
|
+
],
|
|
704
|
+
body: (ctx) => ({ assetId: validThingsId(ctx.str("assetId")) })
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
resource: "asset",
|
|
708
|
+
command: "publish",
|
|
709
|
+
validate: validateAttachmentRole,
|
|
710
|
+
method: "POST",
|
|
711
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/publish-asset`,
|
|
712
|
+
flags: [
|
|
713
|
+
idFlag,
|
|
714
|
+
{
|
|
715
|
+
name: "conversation-id",
|
|
716
|
+
type: "string",
|
|
717
|
+
desc: "Owned conversation containing the artifact"
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: "artifact-id",
|
|
721
|
+
type: "string",
|
|
722
|
+
desc: "Verified file artifact ID"
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
name: "file-token",
|
|
726
|
+
type: "string",
|
|
727
|
+
sensitive: true,
|
|
728
|
+
desc: "Verified directory child file token"
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
name: "source-path",
|
|
732
|
+
type: "string",
|
|
733
|
+
sensitive: true,
|
|
734
|
+
desc: "Absolute delivered file path in this conversation sandbox artifacts directory"
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
name: "run-id",
|
|
738
|
+
type: "string",
|
|
739
|
+
desc: "Verified execution ID, required with --source-path"
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
name: "destination-path",
|
|
743
|
+
type: "string",
|
|
744
|
+
sensitive: true,
|
|
745
|
+
desc: "Existing folder within space documents"
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
name: "role",
|
|
749
|
+
type: "string",
|
|
750
|
+
desc: "attachment (default; only supported role)"
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
name: "confirm-share",
|
|
754
|
+
type: "boolean",
|
|
755
|
+
desc: "User explicitly authorized making this artifact visible to all space members"
|
|
756
|
+
}
|
|
757
|
+
],
|
|
758
|
+
body: (ctx) => {
|
|
759
|
+
if (!ctx.bool("confirmShare"))
|
|
760
|
+
throw new Error(
|
|
761
|
+
"Explicit sharing authorization is required: --confirm-share"
|
|
762
|
+
);
|
|
763
|
+
if ([
|
|
764
|
+
ctx.str("artifactId"),
|
|
765
|
+
ctx.str("fileToken"),
|
|
766
|
+
ctx.str("sourcePath")
|
|
767
|
+
].filter(Boolean).length !== 1)
|
|
768
|
+
throw new Error(
|
|
769
|
+
"Specify exactly one of --artifact-id, --file-token or --source-path"
|
|
770
|
+
);
|
|
771
|
+
if (Boolean(ctx.str("sourcePath")) !== Boolean(ctx.str("runId")))
|
|
772
|
+
throw new Error("--source-path and --run-id must be provided together");
|
|
773
|
+
return {
|
|
774
|
+
...sourceBody(ctx),
|
|
775
|
+
...ctx.str("artifactId") ? { artifactId: validThingsId(ctx.str("artifactId")) } : {},
|
|
776
|
+
...ctx.str("fileToken") ? { fileToken: ctx.str("fileToken") } : {},
|
|
777
|
+
...ctx.str("sourcePath") ? { sourcePath: ctx.str("sourcePath") } : {},
|
|
778
|
+
destinationPath: ctx.str("destinationPath") || null,
|
|
779
|
+
role: ctx.str("role") || "attachment",
|
|
780
|
+
confirmShare: true
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
command: "conversations",
|
|
786
|
+
method: "GET",
|
|
787
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/conversations`,
|
|
788
|
+
flags: [idFlag, ...pageFlags],
|
|
789
|
+
params: pageQuery
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
command: "link-conversation",
|
|
793
|
+
method: "POST",
|
|
794
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/conversations`,
|
|
795
|
+
flags: [
|
|
796
|
+
idFlag,
|
|
797
|
+
{
|
|
798
|
+
name: "conversation-id",
|
|
799
|
+
type: "string",
|
|
800
|
+
required: true,
|
|
801
|
+
desc: "Owned conversation to reference; does not replace its primary thing"
|
|
802
|
+
}
|
|
803
|
+
],
|
|
804
|
+
body: (ctx) => ({
|
|
805
|
+
conversationId: validThingsId(ctx.str("conversationId"))
|
|
806
|
+
})
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
command: "context",
|
|
810
|
+
method: "GET",
|
|
811
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/context`,
|
|
812
|
+
flags: [
|
|
813
|
+
idFlag,
|
|
814
|
+
{
|
|
815
|
+
name: "run-id",
|
|
816
|
+
type: "string",
|
|
817
|
+
desc: "Read this execution snapshot; omitted reads live context"
|
|
818
|
+
}
|
|
819
|
+
],
|
|
820
|
+
params: (ctx) => ctx.str("runId") ? { runId: validThingsId(ctx.str("runId")) } : {}
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
command: "list",
|
|
824
|
+
method: "GET",
|
|
825
|
+
suffix: () => "/things",
|
|
826
|
+
flags: [
|
|
827
|
+
...pageFlags,
|
|
828
|
+
{
|
|
829
|
+
name: "query",
|
|
830
|
+
type: "string",
|
|
831
|
+
sensitive: true,
|
|
832
|
+
desc: "Search title and description"
|
|
833
|
+
},
|
|
834
|
+
{ name: "status", type: "string", desc: "Filter thing status" },
|
|
835
|
+
{ name: "assignee-id", type: "string", desc: "Filter assignee" }
|
|
836
|
+
],
|
|
837
|
+
params: (ctx) => ({
|
|
838
|
+
...pageQuery(ctx),
|
|
839
|
+
...Object.fromEntries(
|
|
840
|
+
["query", "status", "assigneeId"].flatMap(
|
|
841
|
+
(k) => ctx.str(k) ? [[k, ctx.str(k)]] : []
|
|
842
|
+
)
|
|
843
|
+
)
|
|
844
|
+
})
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
command: "get",
|
|
848
|
+
method: "GET",
|
|
849
|
+
suffix: (ctx) => `/things/${thingId(ctx)}`,
|
|
850
|
+
flags: [idFlag]
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
command: "create",
|
|
854
|
+
method: "POST",
|
|
855
|
+
suffix: () => "/things",
|
|
856
|
+
flags: thingFlags,
|
|
857
|
+
body: (ctx) => {
|
|
858
|
+
const fields = thingBody(ctx);
|
|
859
|
+
if (typeof fields.title !== "string" || !fields.title.trim() || typeof fields.description !== "string" || !fields.description.trim())
|
|
860
|
+
throw new Error("Thing creation requires title and description");
|
|
861
|
+
return fields;
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
command: "update",
|
|
866
|
+
method: "PATCH",
|
|
867
|
+
suffix: (ctx) => `/things/${thingId(ctx)}`,
|
|
868
|
+
flags: [idFlag, versionFlag, ...thingFlags],
|
|
869
|
+
body: (ctx) => ({
|
|
870
|
+
...thingBody(ctx),
|
|
871
|
+
expectedVersion: ctx.num("expectedVersion")
|
|
872
|
+
})
|
|
873
|
+
},
|
|
874
|
+
...["archive", "restore"].map((command) => ({
|
|
875
|
+
command,
|
|
876
|
+
method: "POST",
|
|
877
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/${command}`,
|
|
878
|
+
flags: [idFlag, versionFlag],
|
|
879
|
+
body: (ctx) => ({ expectedVersion: ctx.num("expectedVersion") })
|
|
880
|
+
})),
|
|
881
|
+
{
|
|
882
|
+
command: "delete",
|
|
883
|
+
method: "DELETE",
|
|
884
|
+
suffix: (ctx) => `/things/${thingId(ctx)}`,
|
|
885
|
+
flags: [
|
|
886
|
+
idFlag,
|
|
887
|
+
versionFlag,
|
|
888
|
+
{
|
|
889
|
+
name: "confirm-delete",
|
|
890
|
+
type: "boolean",
|
|
891
|
+
desc: "Confirm irreversible deletion of the thing and all links; keep conversations, messages and files"
|
|
892
|
+
}
|
|
893
|
+
],
|
|
894
|
+
validate: (ctx) => {
|
|
895
|
+
if (!ctx.bool("confirmDelete"))
|
|
896
|
+
throw new Error(
|
|
897
|
+
"Explicit deletion confirmation is required: --confirm-delete"
|
|
898
|
+
);
|
|
899
|
+
},
|
|
900
|
+
body: (ctx) => ({
|
|
901
|
+
expectedVersion: ctx.num("expectedVersion"),
|
|
902
|
+
confirmDelete: true
|
|
903
|
+
})
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
resource: "entry",
|
|
907
|
+
command: "list",
|
|
908
|
+
method: "GET",
|
|
909
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/entries`,
|
|
910
|
+
flags: [idFlag, ...pageFlags],
|
|
911
|
+
params: pageQuery
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
resource: "entry",
|
|
915
|
+
command: "append",
|
|
916
|
+
method: "POST",
|
|
917
|
+
suffix: (ctx) => `/things/${thingId(ctx)}/entries`,
|
|
918
|
+
flags: [
|
|
919
|
+
idFlag,
|
|
920
|
+
{
|
|
921
|
+
name: "content",
|
|
922
|
+
type: "string",
|
|
923
|
+
sensitive: true,
|
|
924
|
+
desc: "Entry content"
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
name: "file",
|
|
928
|
+
type: "string",
|
|
929
|
+
sensitive: true,
|
|
930
|
+
desc: "UTF-8 text file"
|
|
931
|
+
},
|
|
932
|
+
{ name: "stdin", type: "boolean", desc: "Read text from stdin" },
|
|
933
|
+
{
|
|
934
|
+
name: "type",
|
|
935
|
+
type: "string",
|
|
936
|
+
desc: "url | note | progress; omitted auto-detects URL or note"
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
name: "title",
|
|
940
|
+
type: "string",
|
|
941
|
+
sensitive: true,
|
|
942
|
+
desc: "Entry title, at most 200 characters"
|
|
943
|
+
}
|
|
944
|
+
],
|
|
945
|
+
validate: (ctx) => {
|
|
946
|
+
if (ctx.str("type") && !["note", "url", "progress"].includes(ctx.str("type")))
|
|
947
|
+
throw new Error("Entry type must be note, url or progress");
|
|
948
|
+
if (ctx.str("title") && !ctx.str("title").trim())
|
|
949
|
+
throw new Error("Entry title must not be blank");
|
|
950
|
+
if (ctx.str("title").trim().length > 200)
|
|
951
|
+
throw new Error("Entry title exceeds 200 characters");
|
|
952
|
+
},
|
|
953
|
+
body: (ctx) => {
|
|
954
|
+
const sources = [
|
|
955
|
+
Boolean(ctx.str("content")),
|
|
956
|
+
Boolean(ctx.str("file")),
|
|
957
|
+
ctx.bool("stdin")
|
|
958
|
+
].filter(Boolean).length;
|
|
959
|
+
if (sources !== 1)
|
|
960
|
+
throw new Error("Specify exactly one of --content, --file or --stdin");
|
|
961
|
+
if (ctx.bool("stdin") && process.stdin.isTTY)
|
|
962
|
+
throw new Error("Pipe text to --stdin");
|
|
963
|
+
return {
|
|
964
|
+
...ctx.str("type") ? { type: ctx.str("type") } : {},
|
|
965
|
+
...ctx.str("title") ? { title: ctx.str("title") } : {},
|
|
966
|
+
content: ctx.str("content") || readFileSync2(ctx.str("file") || 0, "utf8")
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
];
|
|
971
|
+
var thingsCommands = actions.map((action) => ({
|
|
972
|
+
service: "things",
|
|
973
|
+
resource: action.resource,
|
|
974
|
+
command: action.command,
|
|
975
|
+
description: action.resource ? `${action.command} a workspace thing ${action.resource} (Transitional TE REST)` : `${action.command} a workspace thing (Transitional TE REST)`,
|
|
976
|
+
risk: action.risk ?? (action.method === "GET" ? "read" : action.method === "DELETE" ? "high-risk-write" : "write"),
|
|
977
|
+
flags: [
|
|
978
|
+
...targetFlags,
|
|
979
|
+
...action.flags,
|
|
980
|
+
...action.method === "GET" ? [] : [commandFlag]
|
|
981
|
+
],
|
|
982
|
+
validate: (ctx) => {
|
|
983
|
+
thingsTarget(ctx);
|
|
984
|
+
action.suffix(ctx);
|
|
985
|
+
action.params?.(ctx);
|
|
986
|
+
action.validate?.(ctx);
|
|
987
|
+
},
|
|
988
|
+
dryRun: (ctx) => {
|
|
989
|
+
action.validate?.(ctx);
|
|
990
|
+
return {
|
|
991
|
+
method: action.method,
|
|
992
|
+
url: thingsUrl(
|
|
993
|
+
ctx,
|
|
994
|
+
`agent-spaces/${thingsTarget(ctx).agentSpaceId ?? "{resolved-space-id}"}${action.suffix(ctx)}`
|
|
995
|
+
),
|
|
996
|
+
params: {
|
|
997
|
+
target: thingsTarget(ctx),
|
|
998
|
+
resolveTarget: thingsUrl(ctx, "target"),
|
|
999
|
+
...action.params ? { query: "[REDACTED]" } : {}
|
|
1000
|
+
},
|
|
1001
|
+
...action.body ? {
|
|
1002
|
+
body: {
|
|
1003
|
+
payload: "[REDACTED]",
|
|
1004
|
+
commandId: ctx.str("commandId") || "{generated-uuid}"
|
|
1005
|
+
}
|
|
1006
|
+
} : {}
|
|
1007
|
+
};
|
|
1008
|
+
},
|
|
1009
|
+
execute: async (ctx) => {
|
|
1010
|
+
action.validate?.(ctx);
|
|
1011
|
+
const body = action.body?.(ctx);
|
|
1012
|
+
return requestThings(
|
|
1013
|
+
ctx,
|
|
1014
|
+
action.method,
|
|
1015
|
+
`${await root(ctx)}${action.suffix(ctx)}${query(action.params?.(ctx) ?? {})}`,
|
|
1016
|
+
body ? { ...body, commandId: ctx.str("commandId") || randomUUID() } : void 0
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
}));
|
|
1020
|
+
var scopeFlags = [
|
|
1021
|
+
{
|
|
1022
|
+
name: "thing-ids",
|
|
1023
|
+
type: "string",
|
|
1024
|
+
sensitive: true,
|
|
1025
|
+
desc: "Explicit comma-separated thing IDs; cannot combine with assignee scope"
|
|
1026
|
+
},
|
|
1027
|
+
{ name: "assignee-id", type: "string", desc: "Assignee scope" },
|
|
1028
|
+
{
|
|
1029
|
+
name: "from",
|
|
1030
|
+
type: "string",
|
|
1031
|
+
desc: "Inclusive start, ISO timestamp with timezone"
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
name: "to",
|
|
1035
|
+
type: "string",
|
|
1036
|
+
desc: "Exclusive end, ISO timestamp with timezone"
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
name: "time-zone",
|
|
1040
|
+
type: "string",
|
|
1041
|
+
desc: "Calendar timezone, default Asia/Shanghai"
|
|
1042
|
+
}
|
|
1043
|
+
];
|
|
1044
|
+
function explicitIds(ctx) {
|
|
1045
|
+
const ids = [
|
|
1046
|
+
...new Set(
|
|
1047
|
+
ctx.str("thingIds").split(",").map((s) => s.trim()).filter(Boolean).map(validThingsId)
|
|
1048
|
+
)
|
|
1049
|
+
];
|
|
1050
|
+
if (ids.length > 1e3)
|
|
1051
|
+
throw new Error("At most 1000 explicit thing IDs are supported");
|
|
1052
|
+
if (ids.length && ctx.str("assigneeId"))
|
|
1053
|
+
throw new Error("Use explicit IDs or assignee scope");
|
|
1054
|
+
return ids;
|
|
1055
|
+
}
|
|
1056
|
+
thingsCommands.push(
|
|
1057
|
+
...["+detail", "+digest"].map((command) => ({
|
|
1058
|
+
service: "things",
|
|
1059
|
+
command,
|
|
1060
|
+
description: command === "+detail" ? "Collect thing facts and complete timeline with collection boundaries" : "Collect scoped thing facts and period changes for review or summaries",
|
|
1061
|
+
risk: "read",
|
|
1062
|
+
flags: [...targetFlags, ...command === "+detail" ? [idFlag] : scopeFlags],
|
|
1063
|
+
validate: (ctx) => {
|
|
1064
|
+
thingsTarget(ctx);
|
|
1065
|
+
if (command === "+detail") thingId(ctx);
|
|
1066
|
+
else {
|
|
1067
|
+
thingsWindow(ctx);
|
|
1068
|
+
explicitIds(ctx);
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
dryRun: (ctx) => ({
|
|
1072
|
+
method: "GET",
|
|
1073
|
+
url: thingsUrl(ctx, "target"),
|
|
1074
|
+
params: {
|
|
1075
|
+
target: thingsTarget(ctx),
|
|
1076
|
+
operation: command,
|
|
1077
|
+
scope: "[REDACTED]",
|
|
1078
|
+
pagination: true
|
|
1079
|
+
}
|
|
1080
|
+
}),
|
|
1081
|
+
execute: async (ctx) => command === "+detail" ? collectThingDetail(ctx, await root(ctx), thingId(ctx)) : collectThingDigest(ctx, await root(ctx), explicitIds(ctx))
|
|
1082
|
+
}))
|
|
1083
|
+
);
|
|
1084
|
+
var things_default = thingsCommands;
|
|
1085
|
+
export {
|
|
1086
|
+
things_default as default,
|
|
1087
|
+
thingBody,
|
|
1088
|
+
thingsCommands,
|
|
1089
|
+
thingsTarget,
|
|
1090
|
+
validThingsId
|
|
1091
|
+
};
|