@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.
Files changed (185) hide show
  1. package/README.md +35 -10
  2. package/README.zh.md +32 -10
  3. package/bin/ae-cli.js +6 -1
  4. package/cli-installation-guide.md +91 -0
  5. package/dist/{auth-XZNXFRJS.js → auth-MBWRZTB6.js} +171 -13
  6. package/dist/automation-NWWVLWG2.js +459 -0
  7. package/dist/{capability-RJZ4KRGP.js → capability-7SSN6PNZ.js} +11 -6
  8. package/dist/chunk-4655PUNX.js +43 -0
  9. package/dist/{chunk-4NRCTUZJ.js → chunk-5XJYLEVC.js} +4 -4
  10. package/dist/{chunk-JOCDD4ON.js → chunk-7QXISROD.js} +1 -1
  11. package/dist/{chunk-EQ255HKO.js → chunk-AP7YP2NX.js} +2 -2
  12. package/dist/{chunk-DVMLWQD4.js → chunk-CT7QDJS6.js} +2 -2
  13. package/dist/chunk-D6ACFILC.js +56 -0
  14. package/dist/{chunk-HFGZGYCG.js → chunk-EOYSKMXN.js} +264 -10
  15. package/dist/{chunk-57RRFUEZ.js → chunk-FMNNGNYO.js} +43 -8
  16. package/dist/{chunk-7XGFSUOM.js → chunk-GIK6EDUG.js} +291 -84
  17. package/dist/{chunk-WEPZ5M3Z.js → chunk-HBLK3ZHW.js} +7 -4
  18. package/dist/chunk-HVHR4SCP.js +133 -0
  19. package/dist/{chunk-DX5CDO34.js → chunk-KFNMQTZI.js} +580 -214
  20. package/dist/{chunk-HBGADCKA.js → chunk-PLE722AJ.js} +28 -11
  21. package/dist/chunk-RK6GLDGI.js +27 -0
  22. package/dist/{chunk-V2NUHPXF.js → chunk-S6M42KND.js} +1 -1
  23. package/dist/{chunk-7FTTULED.js → chunk-UQ77JXYH.js} +7 -3
  24. package/dist/{chunk-MAPZ7VB6.js → chunk-WNGFSIOB.js} +20 -1
  25. package/dist/{chunk-L2QUIZTS.js → chunk-ZIQWCZTS.js} +3 -3
  26. package/dist/{community-report-client-CU22W53K.js → community-report-client-PEERQCX2.js} +1 -1
  27. package/dist/{config-XO3LI3SA.js → config-FF6YVJKI.js} +29 -10
  28. package/dist/context-YAE3QXP3.js +136 -0
  29. package/dist/{data-integration-HNGUKFIC.js → data-integration-HESZET7E.js} +6 -6
  30. package/dist/index.js +169 -55
  31. package/dist/{local-data-upload-client-GTRIT64F.js → local-data-upload-client-TWMHFLUA.js} +1 -1
  32. package/dist/memory-62BJOULV.js +580 -0
  33. package/dist/{metadata-JAQW7KGZ.js → metadata-7CUMWIB4.js} +7 -7
  34. package/dist/{model-RNPQXIBI.js → model-SBV2JFJI.js} +9 -5
  35. package/dist/{personal-semantic-preference-QCZ2IZTK.js → personal-semantic-preference-6SRCYPGE.js} +119 -11
  36. package/dist/{project-semantic-64JURXKF.js → project-semantic-YYEM4OSU.js} +7 -7
  37. package/dist/{sync-O45NXEQY.js → sync-SU33KYX7.js} +12 -8
  38. package/dist/{te-agent-K5MSPNHJ.js → te-agent-F5QBZSQA.js} +423 -494
  39. package/dist/{te-analysis-KQKCAI5H.js → te-analysis-U4I2W2WC.js} +1090 -67
  40. package/dist/{te-community-4OYU3BDA.js → te-community-PFLDLPP4.js} +3 -3
  41. package/dist/{te-dataops-NFIPB6FX.js → te-dataops-FOQSRIAZ.js} +644 -276
  42. package/dist/{te-engage-HSVSRW22.js → te-engage-ZX76CNAB.js} +6 -6
  43. package/dist/{te-kb-3TS73NO6.js → te-kb-MHDOST62.js} +666 -244
  44. package/dist/{te-system-STMHLS5J.js → te-system-J2FQF5ER.js} +6 -6
  45. package/dist/{te-team-3I5AOX3N.js → te-team-5UOZPTU3.js} +6 -6
  46. package/dist/things-VPPXXLHB.js +1091 -0
  47. package/dist/{update-RZXLPCRH.js → update-EEUTEI6R.js} +59 -51
  48. package/dist/workspace-O3EEIYQM.js +554 -0
  49. package/package.json +30 -11
  50. package/skills/ae-agent/SKILL.md +95 -140
  51. package/skills/ae-agent/references/add-model.md +1 -1
  52. package/skills/ae-agent/references/create-agent.md +1 -1
  53. package/skills/ae-agent/references/find-archived-conversations.md +12 -5
  54. package/skills/ae-agent/references/get-agent.md +1 -1
  55. package/skills/ae-agent/references/list-agents.md +2 -2
  56. package/skills/ae-agent/references/list-models.md +2 -2
  57. package/skills/ae-agent/references/notification.md +40 -0
  58. package/skills/ae-agent/references/restore-conversation.md +3 -1
  59. package/skills/ae-analysis/SKILL.md +76 -15
  60. package/skills/ae-analysis/references/agent_review_submit_to_page.md +2 -0
  61. package/skills/ae-analysis/references/ai_models/event.md +6 -1
  62. package/skills/ae-analysis/references/ai_models/funnel.md +12 -4
  63. package/skills/ae-analysis/references/ai_models/heat_map.md +23 -0
  64. package/skills/ae-analysis/references/ai_models/interval.md +24 -0
  65. package/skills/ae-analysis/references/ai_models/path.md +20 -0
  66. package/skills/ae-analysis/references/ai_models/prop_analysis.md +2 -0
  67. package/skills/ae-analysis/references/ai_models/rank_list.md +30 -0
  68. package/skills/ae-analysis/references/ai_models/retention.md +45 -1
  69. package/skills/ae-analysis/references/ai_models/revenue.md +20 -2
  70. package/skills/ae-analysis/references/ai_models/tag.md +2 -0
  71. package/skills/ae-analysis/references/ai_models.md +96 -0
  72. package/skills/ae-analysis/references/analysis_data_retrieval.md +4 -0
  73. package/skills/ae-analysis/references/asset_batch_info_export.md +10 -0
  74. package/skills/ae-analysis/references/asset_batch_sql_export.md +13 -1
  75. package/skills/ae-analysis/references/asset_export.md +12 -1
  76. package/skills/ae-analysis/references/asset_list.md +1 -0
  77. package/skills/ae-analysis/references/asset_search.md +11 -5
  78. package/skills/ae-analysis/references/bi_panel_list.md +1 -1
  79. package/skills/ae-analysis/references/catalog_list.md +1 -1
  80. package/skills/ae-analysis/references/collaboration.md +48 -0
  81. package/skills/ae-analysis/references/command_index.md +26 -17
  82. package/skills/ae-analysis/references/dashboard_list.md +4 -4
  83. package/skills/ae-analysis/references/dashboard_move.md +21 -0
  84. package/skills/ae-analysis/references/dashboard_report_add.md +2 -0
  85. package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
  86. package/skills/ae-analysis/references/dashboard_report_get.md +19 -0
  87. package/skills/ae-analysis/references/dashboard_report_update.md +27 -0
  88. package/skills/ae-analysis/references/dashboard_update.md +1 -1
  89. package/skills/ae-analysis/references/event_export.md +3 -1
  90. package/skills/ae-analysis/references/event_report_presentation.md +76 -0
  91. package/skills/ae-analysis/references/feedback_submit.md +37 -0
  92. package/skills/ae-analysis/references/governance_recommendation_auto_review.md +71 -0
  93. package/skills/ae-analysis/references/governance_recommendation_export.md +11 -0
  94. package/skills/ae-analysis/references/metadata_resolution.md +18 -3
  95. package/skills/ae-analysis/references/metric_export.md +3 -1
  96. package/skills/ae-analysis/references/metric_list.md +1 -1
  97. package/skills/ae-analysis/references/operation_record_export.md +10 -0
  98. package/skills/ae-analysis/references/personal_semantic_preference_add.md +2 -2
  99. package/skills/ae-analysis/references/personal_semantic_preference_get.md +6 -4
  100. package/skills/ae-analysis/references/personal_semantic_preference_list.md +5 -3
  101. package/skills/ae-analysis/references/personal_semantic_preference_review.md +9 -0
  102. package/skills/ae-analysis/references/personal_semantic_preference_review_list.md +7 -0
  103. package/skills/ae-analysis/references/personal_semantic_preference_submit.md +7 -0
  104. package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +91 -32
  105. package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +99 -1
  106. package/skills/ae-analysis/references/property_export.md +3 -1
  107. package/skills/ae-analysis/references/report_create.md +17 -3
  108. package/skills/ae-analysis/references/report_data_export.md +6 -0
  109. package/skills/ae-analysis/references/report_get.md +7 -1
  110. package/skills/ae-analysis/references/report_list.md +5 -5
  111. package/skills/ae-analysis/references/report_update.md +20 -3
  112. package/skills/ae-analysis/references/sql_table_columns.md +4 -4
  113. package/skills/ae-analysis/references/sql_table_list.md +5 -5
  114. package/skills/ae-analysis/references/system_query_monitor_overview.md +2 -0
  115. package/skills/ae-analysis/references/system_query_task_cancel.md +2 -0
  116. package/skills/ae-analysis/references/system_query_task_export.md +6 -2
  117. package/skills/ae-analysis/references/system_query_task_get.md +2 -0
  118. package/skills/ae-analysis/references/system_query_task_list.md +7 -3
  119. package/skills/ae-analysis/references/system_query_task_options.md +2 -2
  120. package/skills/ae-analysis/references/system_query_task_realtime_list.md +15 -0
  121. package/skills/ae-analysis/references/user_cluster_models.md +8 -0
  122. package/skills/ae-analysis/references/user_tag_create.md +7 -1
  123. package/skills/ae-analysis/references/user_tag_get.md +1 -1
  124. package/skills/ae-analysis/references/user_tag_models.md +20 -2
  125. package/skills/ae-analysis/references/user_tag_refresh.md +1 -1
  126. package/skills/ae-analysis/references/user_tag_update.md +2 -2
  127. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-empty-skeleton.mjs +105 -0
  128. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +669 -29
  129. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +21 -8
  130. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +28 -10
  131. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +66 -0
  132. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +285 -24
  133. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +262 -30
  134. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/plan-kb-source-sync.mjs +1 -1
  135. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/precompiled-source.mjs +46 -2
  136. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/prepare-compile-schema.mjs +64 -0
  137. package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/refresh-state-parts.mjs +91 -0
  138. package/skills/ae-automation/SKILL.md +16 -0
  139. package/skills/ae-automation/references/cli.md +53 -0
  140. package/skills/ae-automation/references/command_index.md +17 -0
  141. package/skills/ae-capability/SKILL.md +73 -2
  142. package/skills/ae-capability/references/collaboration.md +48 -0
  143. package/skills/ae-community/SKILL.md +5 -1
  144. package/skills/ae-community/references/collaboration.md +48 -0
  145. package/skills/ae-current-context/SKILL.md +3 -2
  146. package/skills/ae-data-integration/SKILL.md +4 -0
  147. package/skills/ae-data-integration/references/collaboration.md +48 -0
  148. package/skills/ae-dataops/SKILL.md +54 -74
  149. package/skills/ae-dataops/references/collaboration.md +48 -0
  150. package/skills/ae-dataops/references/dataops-backfill.md +23 -18
  151. package/skills/ae-dataops/references/dataops-flow-create.md +74 -23
  152. package/skills/ae-dataops/references/dataops-flow-monitor.md +45 -13
  153. package/skills/ae-dataops/references/dataops-integration.md +57 -30
  154. package/skills/ae-dataops/references/dataops-query.md +21 -4
  155. package/skills/ae-dataops/references/dataops-table.md +143 -11
  156. package/skills/ae-engage/SKILL.md +21 -6
  157. package/skills/ae-engage/references/channel-mgmt.md +3 -3
  158. package/skills/ae-engage/references/collaboration.md +48 -0
  159. package/skills/ae-engage/references/scene-config-channel.md +4 -4
  160. package/skills/ae-generate-tracking-plan/SKILL.md +4 -0
  161. package/skills/ae-generate-tracking-plan/references/collaboration.md +48 -0
  162. package/skills/ae-kb/SKILL.md +70 -12
  163. package/skills/ae-kb/references/analysis-workflow.md +73 -36
  164. package/skills/ae-kb/references/collaboration.md +48 -0
  165. package/skills/ae-kb/references/query-workflow.md +67 -33
  166. package/skills/ae-kb/references/schema-import.md +32 -0
  167. package/skills/ae-kb/references/source-mutations.md +6 -4
  168. package/skills/ae-kb/references/text-sources.md +53 -0
  169. package/skills/ae-kb-discovery/SKILL.md +8 -3
  170. package/skills/ae-kb-discovery/references/collaboration.md +48 -0
  171. package/skills/ae-metadata/SKILL.md +20 -12
  172. package/skills/ae-metadata/references/collaboration.md +48 -0
  173. package/skills/ae-team/SKILL.md +23 -17
  174. package/skills/ae-things/SKILL.md +85 -0
  175. package/skills/ae-things/references/cli.md +103 -0
  176. package/skills/ae-things-progress/SKILL.md +43 -0
  177. package/skills/ae-things-review/SKILL.md +42 -0
  178. package/skills/ae-workspace/SKILL.md +43 -0
  179. package/skills/ae-workspace/references/commands.md +51 -0
  180. package/dist/chunk-E2JKXMVO.js +0 -29
  181. package/dist/context-IFJI3LIT.js +0 -46
  182. package/dist/memory-QGPSNCQS.js +0 -892
  183. package/skills/ae-agent/references/create-automation.md +0 -125
  184. package/skills/ae-agent/references/list-automations.md +0 -56
  185. package/skills/ae-agent/references/update-automation.md +0 -107
@@ -6,11 +6,11 @@ import {
6
6
  normalizeUrl,
7
7
  safeJsonParse,
8
8
  safeReadJsonFile
9
- } from "./chunk-7FTTULED.js";
9
+ } from "./chunk-UQ77JXYH.js";
10
10
  import {
11
11
  PermissionError,
12
12
  logger
13
- } from "./chunk-MAPZ7VB6.js";
13
+ } from "./chunk-WNGFSIOB.js";
14
14
 
15
15
  // src/core/secure-store.ts
16
16
  import crypto from "crypto";
@@ -28,7 +28,7 @@ var NONCE_LEN = 12;
28
28
  function getMachineId() {
29
29
  if (process.platform === "darwin") {
30
30
  try {
31
- const out = execFileSync("ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"], {
31
+ const out = execFileSync("/usr/sbin/ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"], {
32
32
  encoding: "utf8",
33
33
  timeout: 3e3
34
34
  });
@@ -47,36 +47,42 @@ function getMachineId() {
47
47
  }
48
48
  }
49
49
  if (process.platform === "win32") {
50
- try {
51
- const out = execFileSync(
52
- "reg",
53
- ["query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid"],
54
- { encoding: "utf8", timeout: 3e3 }
55
- );
56
- const match = out.match(/MachineGuid\s+REG_SZ\s+([0-9a-f-]+)/i);
57
- if (match?.[1]) return `win32:${match[1]}`;
58
- } catch {
50
+ const systemRoot = process.env.SystemRoot || process.env.WINDIR;
51
+ const commands = systemRoot && path.win32.isAbsolute(systemRoot) ? [path.win32.join(systemRoot, "System32", "reg.exe"), "reg"] : ["reg"];
52
+ for (const command of commands) {
53
+ try {
54
+ const out = execFileSync(
55
+ command,
56
+ ["query", "HKLM\\SOFTWARE\\Microsoft\\Cryptography", "/v", "MachineGuid"],
57
+ { encoding: "utf8", timeout: 3e3 }
58
+ );
59
+ const match = out.match(/MachineGuid\s+REG_SZ\s+([0-9a-f-]+)/i);
60
+ if (match?.[1]) return `win32:${match[1]}`;
61
+ } catch {
62
+ }
59
63
  }
60
64
  }
61
65
  logger.warn("secure-store: using fallback machine-id (HOME+hostname+platform)");
66
+ return getFallbackMachineId();
67
+ }
68
+ function getFallbackMachineId() {
62
69
  return `fallback:${os.homedir()}|${os.hostname()}|${os.platform()}`;
63
70
  }
64
- var cachedMachineId;
65
- var cachedKey;
66
- function getKey() {
67
- if (!cachedMachineId) cachedMachineId = getMachineId();
68
- if (!cachedKey) {
69
- cachedKey = crypto.scryptSync(cachedMachineId, SCRYPT_SALT, KEY_LEN, {
71
+ var cachedKeys;
72
+ function getKeys() {
73
+ if (!cachedKeys) {
74
+ const machineIds = [.../* @__PURE__ */ new Set([getMachineId(), getFallbackMachineId()])];
75
+ cachedKeys = machineIds.map((machineId) => crypto.scryptSync(machineId, SCRYPT_SALT, KEY_LEN, {
70
76
  N: SCRYPT_N,
71
77
  r: SCRYPT_R,
72
78
  p: SCRYPT_P
73
- });
79
+ }));
74
80
  }
75
- return cachedKey;
81
+ return cachedKeys;
76
82
  }
77
- function encrypt(plaintext) {
83
+ function encrypt(plaintext, key) {
78
84
  const nonce = crypto.randomBytes(NONCE_LEN);
79
- const cipher = crypto.createCipheriv("aes-256-gcm", getKey(), nonce);
85
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, nonce);
80
86
  const data = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
81
87
  return {
82
88
  nonce: nonce.toString("hex"),
@@ -84,8 +90,8 @@ function encrypt(plaintext) {
84
90
  data: data.toString("hex")
85
91
  };
86
92
  }
87
- function decrypt(blob) {
88
- const decipher = crypto.createDecipheriv("aes-256-gcm", getKey(), Buffer.from(blob.nonce, "hex"));
93
+ function decrypt(blob, key) {
94
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, Buffer.from(blob.nonce, "hex"));
89
95
  decipher.setAuthTag(Buffer.from(blob.tag, "hex"));
90
96
  return Buffer.concat([
91
97
  decipher.update(Buffer.from(blob.data, "hex")),
@@ -112,41 +118,81 @@ function ensureStoreDir() {
112
118
  } catch {
113
119
  }
114
120
  }
115
- function atomicWriteEncrypted(filePath, value) {
121
+ function stageFile(filePath, contents) {
116
122
  ensureStoreDir();
117
123
  const tempPath = `${filePath}.${process.pid}.${crypto.randomBytes(6).toString("hex")}.tmp`;
118
- const blob = encrypt(JSON.stringify(value));
119
124
  try {
120
- fs.writeFileSync(tempPath, JSON.stringify(blob, null, 2), { encoding: "utf8", mode: 384 });
125
+ fs.writeFileSync(tempPath, contents, { encoding: "utf8", mode: 384, flag: "wx" });
121
126
  try {
122
127
  fs.chmodSync(tempPath, 384);
123
128
  } catch {
124
129
  }
125
- fs.renameSync(tempPath, filePath);
126
- try {
127
- fs.chmodSync(filePath, 384);
128
- } catch {
129
- }
130
+ return tempPath;
131
+ } catch (error) {
132
+ removeFile(tempPath);
133
+ throw error;
134
+ }
135
+ }
136
+ function prepareEncrypted(filePath, value, companionPath) {
137
+ const existing = readEncryptedFile(filePath);
138
+ const companion = companionPath ? readEncryptedFile(companionPath) : null;
139
+ const key = existing?.key ?? companion?.key ?? getKeys()[0];
140
+ const blob = encrypt(JSON.stringify(value), key);
141
+ return { tempPath: stageFile(filePath, JSON.stringify(blob, null, 2)), previous: existing?.raw ?? null };
142
+ }
143
+ function replaceFile(tempPath, filePath) {
144
+ fs.renameSync(tempPath, filePath);
145
+ try {
146
+ fs.chmodSync(filePath, 384);
147
+ } catch {
148
+ }
149
+ }
150
+ function atomicWriteEncrypted(filePath, value, companionPath) {
151
+ const { tempPath } = prepareEncrypted(filePath, value, companionPath);
152
+ try {
153
+ replaceFile(tempPath, filePath);
130
154
  } finally {
131
- try {
132
- fs.rmSync(tempPath, { force: true });
133
- } catch {
155
+ removeFile(tempPath);
156
+ }
157
+ }
158
+ function readEncryptedFile(filePath) {
159
+ let raw;
160
+ try {
161
+ raw = fs.readFileSync(filePath, "utf8");
162
+ } catch (error) {
163
+ if (error.code === "ENOENT") {
164
+ try {
165
+ if (!fs.lstatSync(filePath, { throwIfNoEntry: false })) return null;
166
+ } catch {
167
+ }
134
168
  }
169
+ throw new CredentialStoreUnreadableError(filePath);
135
170
  }
171
+ return decodeEncryptedFile(filePath, raw);
136
172
  }
137
- function readEncrypted(filePath, label) {
138
- if (!fs.existsSync(filePath)) return null;
173
+ function decodeEncryptedFile(filePath, raw) {
139
174
  try {
140
- const blob = safeJsonParse(fs.readFileSync(filePath, "utf8"));
141
- if (!blob?.nonce || !blob?.tag || !blob?.data) {
142
- logger.warn(`secure-store: malformed ${label}`);
143
- return null;
175
+ const blob = safeJsonParse(raw);
176
+ if (typeof blob?.nonce !== "string" || !/^[0-9a-f]{24}$/i.test(blob.nonce) || typeof blob?.tag !== "string" || !/^[0-9a-f]{32}$/i.test(blob.tag) || typeof blob?.data !== "string" || !/^(?:[0-9a-f]{2})+$/i.test(blob.data)) {
177
+ throw new Error("Malformed encrypted credential");
144
178
  }
145
- return safeJsonParse(decrypt(blob));
146
- } catch (error) {
147
- logger.error(`secure-store: decrypt failed for ${label}: ${error.message}`);
148
- return null;
179
+ for (const key of getKeys()) {
180
+ try {
181
+ return { value: safeJsonParse(decrypt(blob, key)), key, raw };
182
+ } catch {
183
+ }
184
+ }
185
+ } catch {
186
+ }
187
+ throw new CredentialStoreUnreadableError(filePath);
188
+ }
189
+ function readEncrypted(filePath) {
190
+ const result = readEncryptedFile(filePath);
191
+ if (!result) return null;
192
+ if (!result.value || typeof result.value !== "object" || Array.isArray(result.value)) {
193
+ throw new CredentialStoreUnreadableError(filePath);
149
194
  }
195
+ return result.value;
150
196
  }
151
197
  function tokenFingerprint(token) {
152
198
  return crypto.createHash("sha256").update(token).digest("hex").slice(0, 24);
@@ -162,23 +208,139 @@ function legacyProjectionPayload(cliToken) {
162
208
  cliToken
163
209
  };
164
210
  }
165
- function writeLegacyProjection(host, credential) {
166
- atomicWriteEncrypted(legacyFilePath(host), legacyProjectionPayload(credential.cliToken));
167
- return {
168
- credentialId: credential.id,
169
- tokenFingerprint: tokenFingerprint(credential.cliToken)
170
- };
211
+ var activeWrites = /* @__PURE__ */ new Set();
212
+ function recoveryFilePath(host) {
213
+ return `${vaultFilePath(host)}.rollback`;
214
+ }
215
+ function restoreFile(filePath, previous) {
216
+ let current;
217
+ try {
218
+ current = fs.readFileSync(filePath, "utf8");
219
+ } catch (error) {
220
+ if (error.code !== "ENOENT") throw error;
221
+ current = null;
222
+ }
223
+ if (current === previous) return;
224
+ if (previous === null) {
225
+ fs.rmSync(filePath, { force: true });
226
+ return;
227
+ }
228
+ const tempPath = stageFile(filePath, previous);
229
+ try {
230
+ replaceFile(tempPath, filePath);
231
+ } finally {
232
+ removeFile(tempPath);
233
+ }
234
+ }
235
+ function restoreCredentialWrite(host, recovery) {
236
+ restoreFile(legacyFilePath(host), recovery.legacy);
237
+ restoreFile(vaultFilePath(host), recovery.vault);
238
+ for (const name of [recovery.legacyTemp, recovery.vaultTemp]) {
239
+ fs.rmSync(path.join(storeDir(), name), { force: true });
240
+ }
241
+ fs.unlinkSync(recoveryFilePath(host));
242
+ }
243
+ function isRecoveryTemp(name, destination, pid) {
244
+ const prefix = `${path.basename(destination)}.${pid}.`;
245
+ return typeof name === "string" && name.startsWith(prefix) && /^[0-9a-f]{12}\.tmp$/.test(name.slice(prefix.length));
246
+ }
247
+ function recoverCredentialWrite(host) {
248
+ const filePath = recoveryFilePath(host);
249
+ let raw;
250
+ try {
251
+ raw = fs.readFileSync(filePath, "utf8");
252
+ } catch (error) {
253
+ if (error.code === "ENOENT") {
254
+ try {
255
+ if (!fs.lstatSync(filePath, { throwIfNoEntry: false })) return;
256
+ } catch {
257
+ }
258
+ }
259
+ throw new CredentialStoreUnreadableError(filePath);
260
+ }
261
+ try {
262
+ const recovery = safeJsonParse(raw);
263
+ if (recovery?.version !== 1 || !Number.isSafeInteger(recovery.pid) || recovery.pid <= 0 || !(recovery.legacy === null || typeof recovery.legacy === "string") || !(recovery.vault === null || typeof recovery.vault === "string") || !isRecoveryTemp(recovery.legacyTemp, legacyFilePath(host), recovery.pid) || !isRecoveryTemp(recovery.vaultTemp, vaultFilePath(host), recovery.pid) || activeWrites.has(filePath)) throw new Error("Invalid or active credential recovery");
264
+ if (recovery.pid !== process.pid) {
265
+ let ownerExited = false;
266
+ try {
267
+ process.kill(recovery.pid, 0);
268
+ } catch (error) {
269
+ ownerExited = error.code === "ESRCH";
270
+ }
271
+ if (!ownerExited) throw new Error("Credential writer is still running");
272
+ }
273
+ if (recovery.legacy !== null) decodeEncryptedFile(legacyFilePath(host), recovery.legacy);
274
+ if (recovery.vault !== null) decodeEncryptedFile(vaultFilePath(host), recovery.vault);
275
+ restoreCredentialWrite(host, recovery);
276
+ } catch {
277
+ throw new CredentialStoreUnreadableError(filePath);
278
+ }
279
+ }
280
+ function writeVaultAndProjection(host, vault) {
281
+ const active = vault.credentials.find((entry) => entry.id === vault.activeCredentialId);
282
+ vault.legacyProjection = { credentialId: active.id, tokenFingerprint: tokenFingerprint(active.cliToken) };
283
+ const legacyPath = legacyFilePath(host);
284
+ const vaultPath = vaultFilePath(host);
285
+ const recoveryPath = recoveryFilePath(host);
286
+ const staged = [];
287
+ try {
288
+ const legacy = prepareEncrypted(legacyPath, legacyProjectionPayload(active.cliToken), vaultPath);
289
+ staged.push(legacy.tempPath);
290
+ const nextVault = prepareEncrypted(vaultPath, vault, legacyPath);
291
+ staged.push(nextVault.tempPath);
292
+ const recovery = {
293
+ version: 1,
294
+ pid: process.pid,
295
+ legacy: legacy.previous,
296
+ vault: nextVault.previous,
297
+ legacyTemp: path.basename(legacy.tempPath),
298
+ vaultTemp: path.basename(nextVault.tempPath)
299
+ };
300
+ const fd = fs.openSync(recoveryPath, "wx", 384);
301
+ try {
302
+ try {
303
+ fs.writeFileSync(fd, JSON.stringify(recovery), "utf8");
304
+ fs.fsyncSync(fd);
305
+ } finally {
306
+ fs.closeSync(fd);
307
+ }
308
+ } catch (error) {
309
+ removeFile(recoveryPath);
310
+ throw error;
311
+ }
312
+ activeWrites.add(recoveryPath);
313
+ try {
314
+ replaceFile(legacy.tempPath, legacyPath);
315
+ replaceFile(nextVault.tempPath, vaultPath);
316
+ fs.unlinkSync(recoveryPath);
317
+ } catch (error) {
318
+ try {
319
+ restoreCredentialWrite(host, recovery);
320
+ } catch {
321
+ throw new CredentialStoreUnreadableError(recoveryPath);
322
+ }
323
+ throw error;
324
+ } finally {
325
+ activeWrites.delete(recoveryPath);
326
+ }
327
+ } finally {
328
+ for (const tempPath of staged) removeFile(tempPath);
329
+ }
171
330
  }
172
331
  function readVaultRaw(host) {
173
332
  const normalizedHost = normalizeUrl(host);
174
- const vault = readEncrypted(vaultFilePath(normalizedHost), `${normalizedHost} account vault`);
175
- if (!vault || vault.version !== 1 || !Array.isArray(vault.credentials)) return null;
176
- const credentials = vault.credentials.filter((entry) => entry?.id && entry?.cliToken);
177
- if (credentials.length === 0 || !credentials.some((entry) => entry.id === vault.activeCredentialId)) return null;
178
- return { ...vault, host: normalizedHost, credentials };
333
+ recoverCredentialWrite(normalizedHost);
334
+ const filePath = vaultFilePath(normalizedHost);
335
+ const vault = readEncrypted(filePath);
336
+ if (!vault) return null;
337
+ if (vault.version !== 1 || !Array.isArray(vault.credentials) || vault.credentials.length === 0 || !vault.credentials.every((entry) => typeof entry?.id === "string" && entry.id && typeof entry.cliToken === "string" && entry.cliToken.trim()) || !vault.credentials.some((entry) => entry.id === vault.activeCredentialId) || vault.legacyProjection !== void 0 && (!vault.legacyProjection || typeof vault.legacyProjection.credentialId !== "string" || typeof vault.legacyProjection.tokenFingerprint !== "string")) {
338
+ throw new CredentialStoreUnreadableError(filePath);
339
+ }
340
+ return { ...vault, host: normalizedHost };
179
341
  }
180
342
  function writeVault(host, vault) {
181
- atomicWriteEncrypted(vaultFilePath(host), vault);
343
+ atomicWriteEncrypted(vaultFilePath(host), vault, legacyFilePath(host));
182
344
  }
183
345
  function removeFile(filePath) {
184
346
  try {
@@ -187,12 +349,23 @@ function removeFile(filePath) {
187
349
  }
188
350
  }
189
351
  function load(host) {
190
- return readEncrypted(legacyFilePath(host), normalizeUrl(host));
352
+ recoverCredentialWrite(host);
353
+ const filePath = legacyFilePath(host);
354
+ const payload = readEncrypted(filePath);
355
+ if (payload && (typeof payload.accessToken !== "string" || typeof payload.refreshToken !== "string" || typeof payload.accessExpiresAt !== "string" || payload.cliToken !== void 0 && typeof payload.cliToken !== "string")) {
356
+ throw new CredentialStoreUnreadableError(filePath);
357
+ }
358
+ return payload;
359
+ }
360
+ function assertCredentialsReadable(host) {
361
+ readVaultRaw(host);
362
+ load(host);
191
363
  }
192
364
  function loadCredentialVault(host) {
193
365
  const normalizedHost = normalizeUrl(host);
194
366
  let vault = readVaultRaw(normalizedHost);
195
- const legacyToken = load(normalizedHost)?.cliToken?.trim();
367
+ const legacy = load(normalizedHost);
368
+ const legacyToken = legacy?.cliToken?.trim();
196
369
  if (!vault) {
197
370
  if (!legacyToken) return null;
198
371
  const imported = { id: credentialId(legacyToken), cliToken: legacyToken };
@@ -228,7 +401,7 @@ function loadCredentialVault(host) {
228
401
  if (changed) writeVault(normalizedHost, vault);
229
402
  return vault;
230
403
  }
231
- if (vault.legacyProjection) {
404
+ if (vault.legacyProjection && !legacy) {
232
405
  const projection = vault.legacyProjection;
233
406
  const projected = vault.credentials.find((entry) => entry.id === projection.credentialId && tokenFingerprint(entry.cliToken) === projection.tokenFingerprint);
234
407
  if (projected) {
@@ -244,9 +417,7 @@ function loadCredentialVault(host) {
244
417
  vault.activeCredentialId = vault.credentials[0].id;
245
418
  }
246
419
  }
247
- const active = vault.credentials.find((entry) => entry.id === vault.activeCredentialId);
248
- vault.legacyProjection = writeLegacyProjection(normalizedHost, active);
249
- writeVault(normalizedHost, vault);
420
+ writeVaultAndProjection(normalizedHost, vault);
250
421
  return vault;
251
422
  }
252
423
  function getActiveCredential(host) {
@@ -261,7 +432,7 @@ function saveCredential(host, credential, options = {}) {
261
432
  const existingVault = loadCredentialVault(normalizedHost);
262
433
  if (options.add && !credential.account) {
263
434
  throw new SecureStoreAuthError(
264
- `This host does not return account identity from CLI token validation. Upgrade the server before using auth login --add for ${normalizedHost}.`
435
+ `This host does not return account identity from CLI token validation. Upgrade the server before adding another account for ${normalizedHost}.`
265
436
  );
266
437
  }
267
438
  const sameAccount = credential.account ? existingVault?.credentials.find((entry) => entry.account?.openId === credential.account.openId || entry.account?.loginName === credential.account.loginName) : void 0;
@@ -277,13 +448,11 @@ function saveCredential(host, credential, options = {}) {
277
448
  } else {
278
449
  credentials = [saved];
279
450
  }
280
- const legacyProjection = writeLegacyProjection(normalizedHost, saved);
281
- writeVault(normalizedHost, {
451
+ writeVaultAndProjection(normalizedHost, {
282
452
  version: 1,
283
453
  host: normalizedHost,
284
454
  activeCredentialId: saved.id,
285
- credentials,
286
- legacyProjection
455
+ credentials
287
456
  });
288
457
  logger.info(`secure-store: saved CLI credential for ${normalizedHost}`);
289
458
  return saved;
@@ -322,8 +491,7 @@ function activateCredential(host, account) {
322
491
  }
323
492
  const selected = matches[0];
324
493
  vault.activeCredentialId = selected.id;
325
- vault.legacyProjection = writeLegacyProjection(normalizedHost, selected);
326
- writeVault(normalizedHost, vault);
494
+ writeVaultAndProjection(normalizedHost, vault);
327
495
  return selected;
328
496
  }
329
497
  function removeActiveCredential(host) {
@@ -339,12 +507,12 @@ function removeActiveCredential(host) {
339
507
  }
340
508
  const active = vault.credentials[0];
341
509
  vault.activeCredentialId = active.id;
342
- vault.legacyProjection = writeLegacyProjection(normalizedHost, active);
343
- writeVault(normalizedHost, vault);
510
+ writeVaultAndProjection(normalizedHost, vault);
344
511
  return { removed, active };
345
512
  }
346
513
  function clearAllCredentials(host) {
347
514
  const normalizedHost = normalizeUrl(host);
515
+ recoverCredentialWrite(normalizedHost);
348
516
  removeFile(legacyFilePath(normalizedHost));
349
517
  removeFile(vaultFilePath(normalizedHost));
350
518
  logger.info(`secure-store: all CLI credentials cleared for ${normalizedHost}`);
@@ -353,10 +521,20 @@ function loadCliToken(host) {
353
521
  return getActiveCredential(host)?.cliToken ?? null;
354
522
  }
355
523
  var SecureStoreAuthError = class extends Error {
356
- constructor(message) {
524
+ constructor(message, code) {
357
525
  super(message);
526
+ this.code = code;
358
527
  this.name = "SecureStoreAuthError";
359
528
  }
529
+ code;
530
+ };
531
+ var CredentialStoreUnreadableError = class extends Error {
532
+ code = "CREDENTIAL_STORE_UNREADABLE";
533
+ hint = "Keep the existing credential files. Retry in the original OS user and runtime with access to the machine identifier and credential directory. Do not log in again, replace tokens, or log out to fix a local credential read failure.";
534
+ constructor(filePath) {
535
+ super(`Cannot read or decrypt the existing credential file: ${filePath}`);
536
+ this.name = "CredentialStoreUnreadableError";
537
+ }
360
538
  };
361
539
 
362
540
  // src/core/cli-token.ts
@@ -366,6 +544,9 @@ import path2 from "path";
366
544
  var CLI_TOKEN_GENERATE_PATH = "/v1/ta/cli/token/generate";
367
545
  var CLI_TOKEN_RENEW_PATH = "/v1/ta/cli/token/renew";
368
546
  var CLI_TOKEN_VALIDATE_PATH = "/v1/ta/cli/token/validate";
547
+ function safeReturnCode(value) {
548
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
549
+ }
369
550
  var CliTokenValidationUnavailableError = class extends Error {
370
551
  constructor(message) {
371
552
  super(message);
@@ -377,6 +558,15 @@ function isExplicitCliTokenRejection(data, responseText) {
377
558
  const message = String(data?.return_message ?? data?.message ?? data?.error?.message ?? responseText);
378
559
  return /cli[_-]?token[_-]?(invalid|expired)/i.test(code) || /cli[-_\s]?token.*\b(invalid|expired)\b/i.test(message) || /\b(invalid|expired)\b.*cli[-_\s]?token/i.test(message);
379
560
  }
561
+ function cliAccessDisabledDetails(data, responseText) {
562
+ const code = String(data?.code ?? data?.error?.code ?? "");
563
+ const message = String(data?.return_message ?? data?.message ?? data?.error?.message ?? responseText);
564
+ if (code !== "CLI_ACCESS_DISABLED" && !message.includes("CLI_ACCESS_DISABLED")) return void 0;
565
+ return {
566
+ message: message || "CLI access is disabled for this account.",
567
+ hint: data?.hint ?? data?.error?.hint
568
+ };
569
+ }
380
570
  function optionalNonEmptyString(...values) {
381
571
  return values.find((value) => typeof value === "string" && value.trim());
382
572
  }
@@ -475,19 +665,26 @@ async function generateCliToken(hostUrl, accessToken) {
475
665
  body = text ? safeJsonParse(text) : {};
476
666
  } catch {
477
667
  }
478
- const message = body.message ?? body.return_message ?? "CLI access is disabled for this account.";
479
- const code = body.code ?? (String(message).includes("CLI_ACCESS_DISABLED") ? "CLI_ACCESS_DISABLED" : void 0);
480
- throw new PermissionError(message, code, body.hint);
668
+ const serviceMessage = body.message ?? body.return_message;
669
+ const code = body.code === "CLI_ACCESS_DISABLED" || String(serviceMessage).includes("CLI_ACCESS_DISABLED") ? "CLI_ACCESS_DISABLED" : void 0;
670
+ throw new PermissionError(
671
+ code === "CLI_ACCESS_DISABLED" ? "CLI access is disabled for this account." : "You do not have permission to generate a CLI token.",
672
+ code
673
+ );
481
674
  }
482
675
  throw new Error(`CLI token generate HTTP error: ${resp.status} ${resp.statusText}`);
483
676
  }
484
677
  const data = safeJsonParse(await resp.text());
485
678
  if (data.return_code !== 0) {
486
- const message = data.return_message || data.message || "unknown";
487
- if (data.code === "CLI_ACCESS_DISABLED" || String(message).includes("CLI_ACCESS_DISABLED")) {
488
- throw new PermissionError(message, "CLI_ACCESS_DISABLED", data.hint);
679
+ const serviceMessage = data.return_message || data.message;
680
+ if (data.code === "CLI_ACCESS_DISABLED" || String(serviceMessage).includes("CLI_ACCESS_DISABLED")) {
681
+ throw new PermissionError(
682
+ "CLI access is disabled for this account.",
683
+ "CLI_ACCESS_DISABLED"
684
+ );
489
685
  }
490
- throw new Error(`CLI token generate error: ${message} (code: ${data.return_code})`);
686
+ const code = safeReturnCode(data.return_code);
687
+ throw new Error(`CLI token generation failed${code ? ` (code: ${code})` : ""}`);
491
688
  }
492
689
  const cliToken = data.data?.userSecret ?? data.data?.user_secret;
493
690
  if (!cliToken) throw new Error("CLI token generate error: empty userSecret in response");
@@ -511,10 +708,12 @@ async function validateCliTokenOnServer(hostUrl, cliToken) {
511
708
  } catch {
512
709
  body = void 0;
513
710
  }
711
+ const accessDisabled = cliAccessDisabledDetails(body, responseText);
712
+ if (accessDisabled) {
713
+ throw new PermissionError(accessDisabled.message, "CLI_ACCESS_DISABLED", accessDisabled.hint);
714
+ }
514
715
  if (isExplicitCliTokenRejection(body, responseText)) {
515
- throw new SecureStoreAuthError(
516
- `CLI token is invalid or expired for ${hostUrl}. Run: ae-cli auth logout --host ${hostUrl}, then ae-cli auth login --host ${hostUrl}`
517
- );
716
+ throw new SecureStoreAuthError(`CLI token is invalid or expired for ${hostUrl}.`);
518
717
  }
519
718
  if (!resp.ok) {
520
719
  throw new CliTokenValidationUnavailableError(
@@ -578,7 +777,13 @@ function peekCliToken(hostOverride) {
578
777
  const hostUrl = hostOverride || getActiveHost();
579
778
  if (!hostUrl) return void 0;
580
779
  const normalizedHost = normalizeUrl(hostUrl);
581
- const stored = loadCliToken(normalizedHost);
780
+ let stored;
781
+ try {
782
+ stored = loadCliToken(normalizedHost);
783
+ } catch (error) {
784
+ if (error instanceof CredentialStoreUnreadableError) return void 0;
785
+ throw error;
786
+ }
582
787
  if (stored) {
583
788
  cliTokenCache.set(normalizedHost, stored);
584
789
  return stored;
@@ -606,6 +811,7 @@ async function mintCliToken(hostUrl, accessToken) {
606
811
  }
607
812
 
608
813
  export {
814
+ assertCredentialsReadable,
609
815
  getActiveCredential,
610
816
  listCredentials,
611
817
  saveCredential,
@@ -614,6 +820,7 @@ export {
614
820
  removeActiveCredential,
615
821
  clearAllCredentials,
616
822
  SecureStoreAuthError,
823
+ CredentialStoreUnreadableError,
617
824
  CliTokenValidationUnavailableError,
618
825
  clearCliTokenCache,
619
826
  validateCliTokenOnServer,
@@ -6,18 +6,19 @@ import {
6
6
  CapabilityGatewayError,
7
7
  fetchCapabilityGateway,
8
8
  requestCapabilityGateway
9
- } from "./chunk-HFGZGYCG.js";
9
+ } from "./chunk-EOYSKMXN.js";
10
10
  import {
11
11
  readOutputMetadata,
12
12
  unwrapOutputData,
13
13
  withOutputMetadata
14
- } from "./chunk-DX5CDO34.js";
14
+ } from "./chunk-KFNMQTZI.js";
15
15
  import {
16
16
  PermissionError
17
- } from "./chunk-MAPZ7VB6.js";
17
+ } from "./chunk-WNGFSIOB.js";
18
18
 
19
19
  // src/core/analysis-async-artifact.ts
20
20
  import { randomBytes } from "crypto";
21
+ import { once } from "events";
21
22
  import { createWriteStream } from "fs";
22
23
  import { access, link, mkdir, rename, stat, unlink } from "fs/promises";
23
24
  import { Readable } from "stream";
@@ -261,9 +262,11 @@ async function downloadAnalysisArtifact(host, runId, artifactId, output, options
261
262
  if (!response.body) {
262
263
  throw protocolError("Artifact download response has no body.", runId);
263
264
  }
265
+ const destination = createWriteStream(tempPath, { flags: "wx", mode: options.mode });
266
+ await once(destination, "open");
264
267
  tempPresent = true;
265
268
  const source = Readable.fromWeb(response.body);
266
- await pipeline(source, createWriteStream(tempPath, { flags: "wx", mode: options.mode }), {
269
+ await pipeline(source, destination, {
267
270
  signal: options.signal
268
271
  });
269
272
  const file = await stat(tempPath);