@factorialco/fcode-cli 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/i18n/status.js +9 -0
  3. package/dist/commands/modules/pull.js +5 -4
  4. package/dist/commands/modules/push.js +1 -1
  5. package/dist/commands/modules/status.js +9 -0
  6. package/dist/commands/processes/pull.js +5 -4
  7. package/dist/commands/processes/push.js +1 -1
  8. package/dist/commands/processes/status.js +9 -0
  9. package/dist/commands/runtime-env.js +2 -2
  10. package/dist/core/commands/resource-command.d.ts +4 -1
  11. package/dist/core/commands/resource-command.js +9 -2
  12. package/dist/core/dependencies/javascript-env-dependencies.js +4 -4
  13. package/dist/core/dependencies/python-env-dependencies.js +5 -4
  14. package/dist/core/executors/execution-task.js +1 -1
  15. package/dist/core/executors/javascript-execution-task.js +21 -17
  16. package/dist/core/executors/python-execution-task.js +11 -10
  17. package/dist/core/resource-pusher.js +13 -7
  18. package/dist/core/types.d.ts +76 -3
  19. package/dist/core/types.js +33 -6
  20. package/dist/repositories/locale.js +5 -3
  21. package/dist/repositories/process.js +20 -2
  22. package/dist/repositories/script-library.js +3 -2
  23. package/dist/runtime/libs/python/fcode/datastore.py +3 -1
  24. package/dist/services/fcode-graphql-client.d.ts +45 -7
  25. package/dist/services/fcode-graphql-client.js +264 -46
  26. package/dist/services/skills-installer.js +2 -2
  27. package/dist/services/version-pull-reporter.d.ts +20 -0
  28. package/dist/services/version-pull-reporter.js +33 -0
  29. package/dist/utils/child-process.d.ts +26 -0
  30. package/dist/utils/child-process.js +60 -0
  31. package/oclif.manifest.json +1 -1
  32. package/package.json +1 -1
@@ -72,14 +72,27 @@ export interface WorkspaceConfig {
72
72
  export type ResourceRepositoryOptions = {
73
73
  name: string;
74
74
  };
75
+ /**
76
+ * Why a deleted resource is still in the cloud: a workspace version contains one of its published
77
+ * snapshots. The row is read-only there and goes for good once the last of those versions does.
78
+ */
79
+ export type Deletion = {
80
+ deletedAt: string;
81
+ retainingVersionTags: string[];
82
+ };
75
83
  export declare abstract class Resource {
76
84
  abstract readonly contentHash: string;
77
85
  id: string | undefined;
78
86
  slug: string;
79
87
  errorPushing: boolean | undefined;
80
88
  resolvingTeamSlug?: string;
89
+ deletion?: Deletion;
81
90
  sameAs(other: Resource): boolean;
82
91
  }
92
+ /** Whether the workspace may edit the resource: neither a parent's nor a deleted one is its to change. */
93
+ export declare const isReadOnly: (resource: Resource) => boolean;
94
+ /** The sentence `push` and `diff` use to say why a resource is not the workspace's to change. */
95
+ export declare const readOnlyReason: (resource: Resource) => string | undefined;
83
96
  export declare enum OnConflictResolution {
84
97
  KEEP_LOCAL = 0,
85
98
  KEEP_REMOTE = 1
@@ -148,6 +161,62 @@ export interface ProcessUiTrigger {
148
161
  */
149
162
  awaitResult?: boolean;
150
163
  }
164
+ export interface ProcessFactorial {
165
+ /** Master switch: nothing below is exposed while false. */
166
+ enabled: boolean;
167
+ /**
168
+ * Whether Factorial waits for the execution and receives its result. Defaults to true, and is
169
+ * omitted from metadata.json when it does.
170
+ */
171
+ awaitResult?: boolean;
172
+ /**
173
+ * Monolith policy keys the caller must hold: the outer list is an OR of alternatives, each
174
+ * inner list an AND. Free text as far as fcode is concerned. Omitted when empty.
175
+ */
176
+ requiredPolicies?: string[][];
177
+ uiTrigger?: ProcessFactorialUiTrigger;
178
+ form?: ProcessFactorialForm;
179
+ agentTool?: ProcessFactorialAgentTool;
180
+ backend?: ProcessFactorialBackend;
181
+ }
182
+ export interface ProcessFactorialUiTrigger {
183
+ enabled: boolean;
184
+ /** Identifier of the UI location the button is rendered in. Required while enabled. */
185
+ locationId?: string;
186
+ /** Button text; the only field of the block that accepts fcode.i18n("key") tokens. */
187
+ label?: string;
188
+ /** f0 icon name, e.g. "Globe". */
189
+ icon?: string;
190
+ }
191
+ export interface ProcessFactorialForm {
192
+ enabled: boolean;
193
+ /** Whether the form may be embedded anonymously. Omitted from metadata.json when false. */
194
+ public?: boolean;
195
+ /**
196
+ * Whether the app offers the form to its users from its own page in Factorial. The `factorial`
197
+ * block's name for `form.appRole: "USER_FACING_FORM"`. Omitted from metadata.json when false.
198
+ */
199
+ appTool?: boolean;
200
+ }
201
+ export type AgentToolEffect = 'READ' | 'WRITE' | 'DESTRUCTIVE';
202
+ export interface ProcessFactorialAgentTool {
203
+ enabled: boolean;
204
+ /** What the tool does, written for the model. */
205
+ description?: string;
206
+ effect?: AgentToolEffect;
207
+ whenToUse?: string;
208
+ whenNotToUse?: string[];
209
+ preconditions?: string[];
210
+ doesNotDo?: string[];
211
+ /** What the agent should do when the tool is unavailable or fails. */
212
+ degradation?: string;
213
+ /** Slug of the process this one previews the outcome of, when it is a dry run. */
214
+ simulatesFor?: string;
215
+ }
216
+ export interface ProcessFactorialBackend {
217
+ enabled: boolean;
218
+ }
219
+ export type LifecycleRole = 'INSTALL' | 'SETTINGS' | 'UNINSTALL' | 'SYNC';
151
220
  export interface ProcessMetadataFields {
152
221
  name: string;
153
222
  description?: string;
@@ -155,6 +224,7 @@ export interface ProcessMetadataFields {
155
224
  webhook?: ProcessWebhook;
156
225
  form?: ProcessForm;
157
226
  uiTrigger?: ProcessUiTrigger;
227
+ factorial?: ProcessFactorial;
158
228
  }
159
229
  export declare class Process extends Resource {
160
230
  id: string;
@@ -166,6 +236,9 @@ export declare class Process extends Resource {
166
236
  webhook?: ProcessWebhook;
167
237
  form?: ProcessForm;
168
238
  uiTrigger?: ProcessUiTrigger;
239
+ factorial?: ProcessFactorial;
240
+ /** Set by the platform for the reserved lifecycle slugs; not part of the content hash. */
241
+ lifecycleRole?: LifecycleRole;
169
242
  script: {
170
243
  parametersSchema: any;
171
244
  programmingLanguage: ProgrammingLanguage;
@@ -185,7 +258,7 @@ export declare class Process extends Resource {
185
258
  dependencies: {
186
259
  scopedToProcess: boolean;
187
260
  };
188
- }, metadata: ProcessMetadataFields, resolvingTeamSlug?: string);
261
+ }, metadata: ProcessMetadataFields, resolvingTeamSlug?: string, deletion?: Deletion);
189
262
  get contentHash(): string;
190
263
  }
191
264
  export declare class VersionedProcess extends Resource {
@@ -207,7 +280,7 @@ export declare class ScriptLibrary extends Resource {
207
280
  name: string;
208
281
  programmingLanguage: ProgrammingLanguage;
209
282
  sourceCode: string;
210
- constructor(id: string, name: string, sourceCode: string, programmingLanguage: ProgrammingLanguage, resolvingTeamSlug?: string);
283
+ constructor(id: string, name: string, sourceCode: string, programmingLanguage: ProgrammingLanguage, resolvingTeamSlug?: string, deletion?: Deletion);
211
284
  get contentHash(): string;
212
285
  }
213
286
  export declare class Locale extends Resource {
@@ -217,7 +290,7 @@ export declare class Locale extends Resource {
217
290
  slug: string;
218
291
  locale: string;
219
292
  content: string;
220
- constructor(id: string | undefined, locale: string, content: string, resolvingTeamSlug?: string);
293
+ constructor(id: string | undefined, locale: string, content: string, resolvingTeamSlug?: string, deletion?: Deletion);
221
294
  /**
222
295
  * The name a locale is tracked and stored under. Unlike every other resource, the identifier is
223
296
  * not unique: a workspace sees its own `en` and each parent workspace's `en`, and all of them are
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ServiceAccount = exports.Dependency = exports.DependenciesFlags = exports.TeamNameArg = exports.ShowInheritedFlag = exports.ResourceSlugArg = exports.ForceFlag = exports.ScriptLibraryNotFound = exports.ProcessNotFound = exports.WorkspaceSettings = exports.ProgrammingLanguageManifest = exports.Variable = exports.VersionedProgrammingLanguageManifest = exports.VersionedScriptLibrary = exports.Locale = exports.ScriptLibrary = exports.VersionedProcess = exports.Process = exports.DEFAULT_WEBHOOK_AUTH_HEADER = exports.programmingLanguageDisplayName = exports.PROGRAMMING_LANGUAGES = exports.ResourceStatus = exports.OnConflictResolution = exports.Resource = void 0;
3
+ exports.ServiceAccount = exports.Dependency = exports.DependenciesFlags = exports.TeamNameArg = exports.ShowInheritedFlag = exports.ResourceSlugArg = exports.ForceFlag = exports.ScriptLibraryNotFound = exports.ProcessNotFound = exports.WorkspaceSettings = exports.ProgrammingLanguageManifest = exports.Variable = exports.VersionedProgrammingLanguageManifest = exports.VersionedScriptLibrary = exports.Locale = exports.ScriptLibrary = exports.VersionedProcess = exports.Process = exports.DEFAULT_WEBHOOK_AUTH_HEADER = exports.programmingLanguageDisplayName = exports.PROGRAMMING_LANGUAGES = exports.ResourceStatus = exports.OnConflictResolution = exports.readOnlyReason = exports.isReadOnly = exports.Resource = void 0;
4
4
  const core_1 = require("@oclif/core");
5
5
  const crypto = require("node:crypto");
6
6
  const canonical_hash_1 = require("../utils/canonical-hash");
@@ -10,6 +10,27 @@ class Resource {
10
10
  }
11
11
  }
12
12
  exports.Resource = Resource;
13
+ /** Whether the workspace may edit the resource: neither a parent's nor a deleted one is its to change. */
14
+ const isReadOnly = (resource) => Boolean(resource.resolvingTeamSlug || resource.deletion);
15
+ exports.isReadOnly = isReadOnly;
16
+ /** The sentence `push` and `diff` use to say why a resource is not the workspace's to change. */
17
+ const readOnlyReason = (resource) => {
18
+ if (resource.resolvingTeamSlug) {
19
+ return `inherited from team '${resource.resolvingTeamSlug}'`;
20
+ }
21
+ if (resource.deletion) {
22
+ return `deleted in the cloud and kept by workspace version(s) ${resource.deletion.retainingVersionTags.join(', ')}`;
23
+ }
24
+ return undefined;
25
+ };
26
+ exports.readOnlyReason = readOnlyReason;
27
+ /**
28
+ * The deletion as it enters a content hash. A deleted resource must read as changed the moment the
29
+ * cloud deletes it — or brings it back — so a pull marks its files read-only (or writable again)
30
+ * even though their content did not move; a live resource contributes nothing, so no stored hash
31
+ * changes for it.
32
+ */
33
+ const deletionHashPart = (deletion) => deletion ? JSON.stringify({ deletedAt: deletion.deletedAt, retainingVersionTags: [...deletion.retainingVersionTags].sort() }) : '';
13
34
  var OnConflictResolution;
14
35
  (function (OnConflictResolution) {
15
36
  OnConflictResolution[OnConflictResolution["KEEP_LOCAL"] = 0] = "KEEP_LOCAL";
@@ -41,16 +62,18 @@ exports.programmingLanguageDisplayName = programmingLanguageDisplayName;
41
62
  // The header assumed when none is configured; its value carries a Bearer scheme.
42
63
  exports.DEFAULT_WEBHOOK_AUTH_HEADER = 'Authorization';
43
64
  class Process extends Resource {
44
- constructor(id, slug, script, readme, manifest, settings, metadata, resolvingTeamSlug) {
65
+ constructor(id, slug, script, readme, manifest, settings, metadata, resolvingTeamSlug, deletion) {
45
66
  super();
46
67
  this.id = id;
47
68
  this.slug = slug;
69
+ this.deletion = deletion;
48
70
  this.name = metadata.name;
49
71
  this.description = metadata.description;
50
72
  this.tags = metadata.tags;
51
73
  this.webhook = metadata.webhook;
52
74
  this.form = metadata.form;
53
75
  this.uiTrigger = metadata.uiTrigger;
76
+ this.factorial = metadata.factorial;
54
77
  this.script = script;
55
78
  this.readme = readme;
56
79
  this.manifest = settings.dependencies.scopedToProcess && manifest !== null ? manifest : { dependencies: [] };
@@ -70,8 +93,10 @@ class Process extends Resource {
70
93
  // Inserted only when set, so every process that predates UI triggers keeps the
71
94
  // content hash already stored in .fcode (mirrors WorkspaceSettings.contentHash).
72
95
  ...(this.uiTrigger && { uiTrigger: this.uiTrigger }),
96
+ ...(this.factorial && { factorial: this.factorial }),
73
97
  manifestDependencies: this.manifest.dependencies,
74
98
  dependenciesScopedToProcess: this.settings.dependencies.scopedToProcess,
99
+ ...(this.deletion && { deletion: deletionHashPart(this.deletion) }),
75
100
  });
76
101
  }
77
102
  }
@@ -94,7 +119,7 @@ class VersionedProcess extends Resource {
94
119
  }
95
120
  exports.VersionedProcess = VersionedProcess;
96
121
  class ScriptLibrary extends Resource {
97
- constructor(id, name, sourceCode, programmingLanguage, resolvingTeamSlug) {
122
+ constructor(id, name, sourceCode, programmingLanguage, resolvingTeamSlug, deletion) {
98
123
  super();
99
124
  this.id = id;
100
125
  this.slug = name;
@@ -102,20 +127,22 @@ class ScriptLibrary extends Resource {
102
127
  this.sourceCode = sourceCode;
103
128
  this.programmingLanguage = programmingLanguage;
104
129
  this.resolvingTeamSlug = resolvingTeamSlug;
130
+ this.deletion = deletion;
105
131
  }
106
132
  get contentHash() {
107
- return crypto.createHash('md5').update(this.sourceCode).digest('hex');
133
+ return crypto.createHash('md5').update(this.sourceCode).update(deletionHashPart(this.deletion)).digest('hex');
108
134
  }
109
135
  }
110
136
  exports.ScriptLibrary = ScriptLibrary;
111
137
  class Locale extends Resource {
112
- constructor(id, locale, content, resolvingTeamSlug) {
138
+ constructor(id, locale, content, resolvingTeamSlug, deletion) {
113
139
  super();
114
140
  this.id = id;
115
141
  this.slug = Locale.slugFor(locale, resolvingTeamSlug);
116
142
  this.locale = locale;
117
143
  this.content = content;
118
144
  this.resolvingTeamSlug = resolvingTeamSlug;
145
+ this.deletion = deletion;
119
146
  }
120
147
  /**
121
148
  * The name a locale is tracked and stored under. Unlike every other resource, the identifier is
@@ -133,7 +160,7 @@ class Locale extends Resource {
133
160
  // Hashed over the raw YAML: the file is the source of truth and round-trips comments and
134
161
  // ordering, so any edit — even one that parses to the same translations — is a change to push.
135
162
  get contentHash() {
136
- return crypto.createHash('md5').update(this.content).digest('hex');
163
+ return crypto.createHash('md5').update(this.content).update(deletionHashPart(this.deletion)).digest('hex');
137
164
  }
138
165
  }
139
166
  exports.Locale = Locale;
@@ -32,7 +32,7 @@ class LocaleRepository extends resource_1.default {
32
32
  }
33
33
  try {
34
34
  const content = fs.readFileSync(this.getResourcePath(localeMetadata)).toString();
35
- return new types_1.Locale(localeMetadata.id, localeMetadata.locale ?? slug, content, localeMetadata.resolvingTeamSlug);
35
+ return new types_1.Locale(localeMetadata.id, localeMetadata.locale ?? slug, content, localeMetadata.resolvingTeamSlug, localeMetadata.deletion);
36
36
  }
37
37
  catch (error) {
38
38
  throw new errors_1.LocalLocaleNotFound(error, slug);
@@ -78,12 +78,14 @@ class LocaleRepository extends resource_1.default {
78
78
  locale: locale.locale,
79
79
  slug: locale.slug,
80
80
  ...(locale.resolvingTeamSlug && { resolvingTeamSlug: locale.resolvingTeamSlug }),
81
+ ...(locale.deletion && { deletion: locale.deletion }),
81
82
  };
82
83
  }
83
84
  async saveFiles(locale) {
84
85
  // Inherited locales are written read-only, like inherited modules: they belong to a parent
85
- // workspace, and editing one here would push an override rather than change the parent.
86
- (0, file_utils_1.outputFileSyncIfChanged)(this.getResourcePath(locale), locale.content || '', { readOnly: Boolean(locale.resolvingTeamSlug) });
86
+ // workspace, and editing one here would push an override rather than change the parent. A
87
+ // deleted locale is read-only too: only its versions are still resolved.
88
+ (0, file_utils_1.outputFileSyncIfChanged)(this.getResourcePath(locale), locale.content || '', { readOnly: (0, types_1.isReadOnly)(locale) });
87
89
  }
88
90
  async metadataFromFiles(slug) {
89
91
  return {
@@ -37,8 +37,23 @@ function buildProcessMetadata(process) {
37
37
  if (process.uiTrigger !== undefined) {
38
38
  metadata.uiTrigger = process.uiTrigger;
39
39
  }
40
+ if (process.factorial !== undefined) {
41
+ metadata.factorial = process.factorial;
42
+ }
40
43
  return metadata;
41
44
  }
45
+ /**
46
+ * The `factorial` block as the file has it, minus the `title` and `description` keys an earlier
47
+ * draft of the block carried: the process's own name and description took their place, so a file
48
+ * that still has them is read as if it did not, and the next save drops them.
49
+ */
50
+ function readFactorialBlock(raw) {
51
+ if (raw === undefined || raw === null || typeof raw !== 'object') {
52
+ return raw ?? undefined;
53
+ }
54
+ const { title: _title, description: _description, ...factorial } = raw;
55
+ return factorial;
56
+ }
42
57
  const PROCESS_SOURCE_CODE_FILE_NAME = (programmingLanguage) => (programmingLanguage === 'PYTHON' ? 'main.py' : 'index.js');
43
58
  exports.PROCESS_SOURCE_CODE_FILE_NAME = PROCESS_SOURCE_CODE_FILE_NAME;
44
59
  const PROCESS_DEPENDENCIES_FILE_NAME = (programmingLanguage) => PROGRAMMING_LANGUAGE_DEPENDENCIES_FILE_NAME[programmingLanguage];
@@ -147,7 +162,7 @@ class ProcessRepository extends resource_1.default {
147
162
  const manifest = isDependenciesFilePresent
148
163
  ? { dependencies: (0, dependencies_1.dependenciesFromFile)(processMetadata.script.programmingLanguage, fs.readFileSync(dependenciesFile).toString()) }
149
164
  : null;
150
- return new types_1.Process(processMetadata.id, processMetadata.slug, { parametersSchema, programmingLanguage: processMetadata.script.programmingLanguage, sourceCode }, readme, manifest, { dependencies: { scopedToProcess: isDependenciesFilePresent } }, metadata, processMetadata.resolvingTeamSlug);
165
+ return new types_1.Process(processMetadata.id, processMetadata.slug, { parametersSchema, programmingLanguage: processMetadata.script.programmingLanguage, sourceCode }, readme, manifest, { dependencies: { scopedToProcess: isDependenciesFilePresent } }, metadata, processMetadata.resolvingTeamSlug, processMetadata.deletion);
151
166
  }
152
167
  catch {
153
168
  throw new Error(`Process ${processSlug} not found!`);
@@ -163,6 +178,7 @@ class ProcessRepository extends resource_1.default {
163
178
  webhook: raw.webhook,
164
179
  form: raw.form,
165
180
  uiTrigger: raw.uiTrigger,
181
+ factorial: readFactorialBlock(raw.factorial),
166
182
  };
167
183
  }
168
184
  catch (error) {
@@ -229,6 +245,7 @@ class ProcessRepository extends resource_1.default {
229
245
  programmingLanguage: process.script.programmingLanguage,
230
246
  },
231
247
  ...(process.resolvingTeamSlug && { resolvingTeamSlug: process.resolvingTeamSlug }),
248
+ ...(process.deletion && { deletion: process.deletion }),
232
249
  };
233
250
  }
234
251
  async metadataFromFiles(slug) {
@@ -243,7 +260,8 @@ class ProcessRepository extends resource_1.default {
243
260
  };
244
261
  }
245
262
  async saveFiles(process) {
246
- const readOnly = Boolean(process.resolvingTeamSlug);
263
+ // A deleted process is kept exactly as its versions left it, like an inherited one: read-only.
264
+ const readOnly = (0, types_1.isReadOnly)(process);
247
265
  (0, file_utils_1.outputFileSyncIfChanged)(this.buildResourcePath(process, this.getSourceCodeFileName(process.script.programmingLanguage)), process.script.sourceCode || '', {
248
266
  readOnly,
249
267
  });
@@ -25,7 +25,7 @@ class ScriptLibraryRepository extends resource_1.default {
25
25
  const sourceCodeFile = fs.readFileSync(this.getResourcePath(scriptLibraryMetadata));
26
26
  try {
27
27
  const sourceCode = sourceCodeFile.toString();
28
- return new types_1.ScriptLibrary(scriptLibraryMetadata.id, scriptLibraryMetadata.name, sourceCode, scriptLibraryMetadata.programmingLanguage, scriptLibraryMetadata.resolvingTeamSlug);
28
+ return new types_1.ScriptLibrary(scriptLibraryMetadata.id, scriptLibraryMetadata.name, sourceCode, scriptLibraryMetadata.programmingLanguage, scriptLibraryMetadata.resolvingTeamSlug, scriptLibraryMetadata.deletion);
29
29
  }
30
30
  catch (error) {
31
31
  throw new errors_1.LocalScriptLibraryNotFound(error, slug);
@@ -83,10 +83,11 @@ class ScriptLibraryRepository extends resource_1.default {
83
83
  slug: scriptLibrary.slug,
84
84
  programmingLanguage: scriptLibrary.programmingLanguage,
85
85
  ...(scriptLibrary.resolvingTeamSlug && { resolvingTeamSlug: scriptLibrary.resolvingTeamSlug }),
86
+ ...(scriptLibrary.deletion && { deletion: scriptLibrary.deletion }),
86
87
  };
87
88
  }
88
89
  async saveFiles(scriptLibrary) {
89
- (0, file_utils_1.outputFileSyncIfChanged)(this.getResourcePath(scriptLibrary), scriptLibrary.sourceCode || '', { readOnly: Boolean(scriptLibrary.resolvingTeamSlug) });
90
+ (0, file_utils_1.outputFileSyncIfChanged)(this.getResourcePath(scriptLibrary), scriptLibrary.sourceCode || '', { readOnly: (0, types_1.isReadOnly)(scriptLibrary) });
90
91
  }
91
92
  versionsDirectory(scriptLibrary) {
92
93
  return path.join(this._repositoryName, this.resourceDirectoryName(scriptLibrary), 'versions');
@@ -21,7 +21,9 @@ class Datastore:
21
21
  return self.getAll().get(key, None)
22
22
  raise TypeError("Invalid argument type")
23
23
 
24
- def set(self, key, value):
24
+ def set(self, key, value, encrypted=False):
25
+ if not isinstance(encrypted, bool):
26
+ raise TypeError("Invalid encrypted flag. Encrypted must be a boolean.")
25
27
  if isinstance(key, (str, int)) and isinstance(value, (str, int)):
26
28
  datastore = self.getAll()
27
29
  datastore[key] = value
@@ -1,5 +1,14 @@
1
1
  import { GraphQLClient } from 'graphql-request';
2
2
  import { Locale, Process, ProgrammingLanguage, ProgrammingLanguageManifest, RawTeamSettings, ScriptLibrary, TeamUpdateInput, TeamVersion, TeamVersionAlias, Variable, VersionedProcess, VersionedProgrammingLanguageManifest, VersionedScriptLibrary, ServiceAccount } from '../core/types';
3
+ /**
4
+ * What a delete mutation answers. `deletedAt` is set when the entity was kept as deleted because a
5
+ * workspace version still contains it; `retainingVersionTags` names those versions.
6
+ */
7
+ export interface RemovedResource {
8
+ id: string;
9
+ deletedAt: string | null;
10
+ retainingVersionTags: string[];
11
+ }
3
12
  export type FcodeGraphQLClientOptions = {
4
13
  url: string;
5
14
  accessToken: string;
@@ -16,10 +25,17 @@ declare class FcodeGraphQLClient {
16
25
  cleanError(error: any): any;
17
26
  private cloudUnavailableMessage;
18
27
  private isNetworkError;
19
- allProcesses(): Promise<Array<Process>>;
28
+ /**
29
+ * Every process of the workspace, the deleted ones a workspace version still contains included:
30
+ * they are pulled read-only with their versions, so the local copy keeps what the versions run.
31
+ * An api that predates deleted-marked processes rejects the query over the unknown field, and
32
+ * the fallback lists the live ones as it always did.
33
+ */
34
+ allProcesses(includeDeleted?: boolean): Promise<Array<Process>>;
20
35
  allVersionedProcesses(processId: string): Promise<Array<VersionedProcess>>;
21
36
  createVersionedProcesses(versionedProcess: VersionedProcess): Promise<void>;
22
- allScriptLibraries(): Promise<Array<ScriptLibrary>>;
37
+ /** Same deleted-inclusive listing, and the same fallback, as {@link allProcesses}. */
38
+ allScriptLibraries(includeDeleted?: boolean): Promise<Array<ScriptLibrary>>;
23
39
  allVersionedScriptLibraries(scriptLibraryId: string): Promise<Array<VersionedScriptLibrary>>;
24
40
  createVersionedScriptLibrary(versionedScriptLibrary: VersionedScriptLibrary): Promise<void>;
25
41
  allVariables(): Promise<Array<Variable>>;
@@ -29,26 +45,48 @@ declare class FcodeGraphQLClient {
29
45
  * kept twice here — an override is layered over the parent's file key by key, so the parent's
30
46
  * keys are still what the ones it does not mention resolve to.
31
47
  */
32
- allLocales(): Promise<Array<Locale>>;
48
+ allLocales(includeDeleted?: boolean): Promise<Array<Locale>>;
49
+ private fetchLocales;
33
50
  pushLocale(locale: Locale): Promise<Locale>;
34
51
  updateLocale(locale: Locale): Promise<Locale>;
35
- removeLocale(locale: string | undefined): Promise<void>;
52
+ removeLocale(locale: string | undefined): Promise<RemovedResource>;
36
53
  private toProcessInput;
37
54
  pushProcess(process: Process): Promise<Process>;
38
- removeProcess(id: String | undefined): Promise<Process>;
55
+ removeProcess(id: String | undefined): Promise<RemovedResource>;
39
56
  pushScriptLibrary(scriptLibrary: ScriptLibrary): Promise<ScriptLibrary>;
40
- removeScriptLibrary(id: String | undefined): Promise<Process>;
57
+ removeScriptLibrary(id: String | undefined): Promise<RemovedResource>;
41
58
  pushVariable(variable: Variable): Promise<Variable>;
42
59
  updateVariable(variable: Variable): Promise<Variable>;
43
60
  removeVariable(id: String | undefined): Promise<Process>;
44
61
  programmingLanguageManifest(programmingLanguage: ProgrammingLanguage): Promise<ProgrammingLanguageManifest>;
45
62
  private inheritedTeam;
63
+ private deletionOf;
64
+ private isUndefinedDeletionFieldError;
46
65
  /**
47
66
  * The public mode and the default header name are left out, so a public webhook — or one
48
67
  * using the default header — keeps the metadata.json it already had on disk.
49
68
  */
50
69
  private mapWebhook;
51
- mapProcess({ id, slug, name, description, tags, script, readme, manifest, settings, triggers, resolvingTeamSlug }: any): Process;
70
+ /**
71
+ * metadata.json omits every defaulted field of the `factorial` block, so the input restores
72
+ * them explicitly: every input field left out means "leave unchanged" on the platform, and the
73
+ * file is the source of truth. That includes the agent tool's clearable texts, sent as "" when
74
+ * the file has none so deleting the line clears the value. The platform reads a null or empty
75
+ * `uiTrigger.locationId` / `label` / `icon` and `agentTool.effect` as unchanged, though, so
76
+ * those are sent only when present (like the legacy `uiTrigger.label`).
77
+ */
78
+ private toFactorialInput;
79
+ /**
80
+ * The `factorial` block as metadata.json writes it: defaulted fields omitted, and a block or
81
+ * sub-block omitted only when disabled AND all defaults — a disabled sub-block that still carries
82
+ * settings (a tool contract, a trigger location, a public form) is kept, or a pull followed by a
83
+ * push would clear them on the platform. The platform always returns the block, so a process
84
+ * that never configured one comes back as all defaults and is mapped to no block at all, or every
85
+ * process in every workspace would gain a `factorial` key (and a new content hash) on its next
86
+ * pull.
87
+ */
88
+ private mapFactorialSettings;
89
+ mapProcess({ id, slug, name, description, tags, script, readme, manifest, settings, triggers, resolvingTeamSlug, lifecycleRole, deletedAt, retainingVersionTags, }: any): Process;
52
90
  /**
53
91
  * GraphQL nests the webhook configuration under `settings`, while settings.json and the REST API
54
92
  * keep it flat. Mapping it explicitly is what keeps that mismatch from silently reading as