@withone/cli 1.55.0 → 1.55.1
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 +5 -0
- package/dist/index.js +176 -145
- package/package.json +1 -1
- package/skills/one/references/flows.md +6 -0
package/README.md
CHANGED
|
@@ -587,8 +587,13 @@ Resume a paused or failed workflow run from where it left off.
|
|
|
587
587
|
|
|
588
588
|
```bash
|
|
589
589
|
one flow resume abc123
|
|
590
|
+
one flow resume abc123 --allow-bash # required if the flow has bash steps
|
|
590
591
|
```
|
|
591
592
|
|
|
593
|
+
`--allow-bash` is gated the same way as on `flow execute` — resuming doesn't
|
|
594
|
+
inherit the permission from the original run, so pass it again. `one flow list`
|
|
595
|
+
shows which flows need it.
|
|
596
|
+
|
|
592
597
|
### `one flow runs [flowKey]`
|
|
593
598
|
|
|
594
599
|
List workflow runs, optionally filtered by workflow key.
|
package/dist/index.js
CHANGED
|
@@ -150,15 +150,15 @@ import {
|
|
|
150
150
|
|
|
151
151
|
// src/cli.ts
|
|
152
152
|
import { createRequire as createRequire3 } from "module";
|
|
153
|
-
import
|
|
153
|
+
import path12 from "path";
|
|
154
154
|
import { Command } from "commander";
|
|
155
155
|
|
|
156
156
|
// src/commands/init.ts
|
|
157
157
|
import * as p3 from "@clack/prompts";
|
|
158
158
|
import pc2 from "picocolors";
|
|
159
159
|
import fs3 from "fs";
|
|
160
|
-
import
|
|
161
|
-
import { fileURLToPath as
|
|
160
|
+
import path4 from "path";
|
|
161
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
162
162
|
|
|
163
163
|
// src/lib/agents.ts
|
|
164
164
|
import fs from "fs";
|
|
@@ -649,16 +649,42 @@ import open2 from "open";
|
|
|
649
649
|
|
|
650
650
|
// src/lib/skill-sync.ts
|
|
651
651
|
import fs2 from "fs";
|
|
652
|
-
import
|
|
653
|
-
import { fileURLToPath } from "url";
|
|
652
|
+
import path3 from "path";
|
|
653
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
654
654
|
|
|
655
655
|
// src/commands/update.ts
|
|
656
|
-
import { createRequire } from "module";
|
|
657
656
|
import { spawn } from "child_process";
|
|
658
657
|
import { readFileSync, writeFileSync, mkdirSync, rmSync } from "fs";
|
|
659
658
|
import { join } from "path";
|
|
659
|
+
|
|
660
|
+
// src/lib/version.ts
|
|
661
|
+
import { createRequire } from "module";
|
|
662
|
+
import { existsSync } from "fs";
|
|
663
|
+
import path2 from "path";
|
|
664
|
+
import { fileURLToPath } from "url";
|
|
660
665
|
var require2 = createRequire(import.meta.url);
|
|
661
|
-
var
|
|
666
|
+
var cached = null;
|
|
667
|
+
function cliVersion() {
|
|
668
|
+
if (cached !== null) return cached;
|
|
669
|
+
const dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
670
|
+
for (let i = 1; i <= 4; i++) {
|
|
671
|
+
const candidate = path2.resolve(dir, ...Array(i).fill(".."), "package.json");
|
|
672
|
+
if (!existsSync(candidate)) continue;
|
|
673
|
+
try {
|
|
674
|
+
const version2 = require2(candidate).version;
|
|
675
|
+
if (version2) {
|
|
676
|
+
cached = version2;
|
|
677
|
+
return cached;
|
|
678
|
+
}
|
|
679
|
+
} catch {
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
cached = "unknown";
|
|
683
|
+
return cached;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/commands/update.ts
|
|
687
|
+
var currentVersion = cliVersion();
|
|
662
688
|
var ONE_DIR = () => join(homeDir(), ".one");
|
|
663
689
|
var CACHE_PATH = () => join(ONE_DIR(), "update-check.json");
|
|
664
690
|
var LOCK_PATH = () => join(ONE_DIR(), "auto-update.lock");
|
|
@@ -814,17 +840,17 @@ function autoUpdate(targetVersion, publishedAt) {
|
|
|
814
840
|
var CANONICAL_SKILL_DIR = ".agents/skills";
|
|
815
841
|
var VERSION_MARKER = ".one-cli-version";
|
|
816
842
|
function getPackagedSkillDir() {
|
|
817
|
-
const here =
|
|
818
|
-
return
|
|
843
|
+
const here = path3.dirname(fileURLToPath2(import.meta.url));
|
|
844
|
+
return path3.resolve(here, "..", "skills", "one");
|
|
819
845
|
}
|
|
820
846
|
function getCanonicalSkillPath() {
|
|
821
|
-
return
|
|
847
|
+
return path3.join(homeDir(), CANONICAL_SKILL_DIR, "one");
|
|
822
848
|
}
|
|
823
849
|
function getVersionMarkerPath() {
|
|
824
|
-
return
|
|
850
|
+
return path3.join(getCanonicalSkillPath(), VERSION_MARKER);
|
|
825
851
|
}
|
|
826
852
|
function isSkillInstalled() {
|
|
827
|
-
return fs2.existsSync(
|
|
853
|
+
return fs2.existsSync(path3.join(getCanonicalSkillPath(), "SKILL.md"));
|
|
828
854
|
}
|
|
829
855
|
function readInstalledSkillVersion() {
|
|
830
856
|
try {
|
|
@@ -844,8 +870,8 @@ function writeInstalledSkillVersion(version2) {
|
|
|
844
870
|
function copyDirSync(src, dest) {
|
|
845
871
|
fs2.mkdirSync(dest, { recursive: true });
|
|
846
872
|
for (const entry of fs2.readdirSync(src, { withFileTypes: true })) {
|
|
847
|
-
const srcPath =
|
|
848
|
-
const destPath =
|
|
873
|
+
const srcPath = path3.join(src, entry.name);
|
|
874
|
+
const destPath = path3.join(dest, entry.name);
|
|
849
875
|
if (entry.isDirectory()) {
|
|
850
876
|
copyDirSync(srcPath, destPath);
|
|
851
877
|
} else {
|
|
@@ -872,7 +898,7 @@ function forceSyncSkills() {
|
|
|
872
898
|
}
|
|
873
899
|
function performSync(current, reason) {
|
|
874
900
|
const source = getPackagedSkillDir();
|
|
875
|
-
if (!fs2.existsSync(
|
|
901
|
+
if (!fs2.existsSync(path3.join(source, "SKILL.md"))) {
|
|
876
902
|
return { synced: false, reason: "source-missing" };
|
|
877
903
|
}
|
|
878
904
|
const canonical = getCanonicalSkillPath();
|
|
@@ -1240,7 +1266,7 @@ async function chooseConfigScope(options) {
|
|
|
1240
1266
|
const hasGlobal = globalConfigExists();
|
|
1241
1267
|
const hasProject = projectConfigExists();
|
|
1242
1268
|
const projectRoot = resolved.projectRoot;
|
|
1243
|
-
const projectName =
|
|
1269
|
+
const projectName = path4.basename(projectRoot);
|
|
1244
1270
|
const homeGlobal = tildify(getGlobalConfigPath());
|
|
1245
1271
|
const homeProject = tildify(getProjectConfigPath(projectRoot));
|
|
1246
1272
|
if (hasProject) {
|
|
@@ -1525,26 +1551,26 @@ var SKILL_AGENTS = [
|
|
|
1525
1551
|
];
|
|
1526
1552
|
var CANONICAL_SKILL_DIR2 = ".agents/skills";
|
|
1527
1553
|
function getSkillSourceDir() {
|
|
1528
|
-
const __dirname2 =
|
|
1529
|
-
return
|
|
1554
|
+
const __dirname2 = path4.dirname(fileURLToPath3(import.meta.url));
|
|
1555
|
+
return path4.resolve(__dirname2, "..", "skills", "one");
|
|
1530
1556
|
}
|
|
1531
1557
|
function getCanonicalSkillPath2() {
|
|
1532
|
-
return
|
|
1558
|
+
return path4.join(homeDir(), CANONICAL_SKILL_DIR2, "one");
|
|
1533
1559
|
}
|
|
1534
1560
|
function getAgentSkillPath(agent) {
|
|
1535
|
-
return
|
|
1561
|
+
return path4.join(homeDir(), agent.skillDir, "one");
|
|
1536
1562
|
}
|
|
1537
1563
|
function isSkillInstalled2() {
|
|
1538
|
-
return fs3.existsSync(
|
|
1564
|
+
return fs3.existsSync(path4.join(getCanonicalSkillPath2(), "SKILL.md"));
|
|
1539
1565
|
}
|
|
1540
1566
|
function isSkillInstalledForAgent(agent) {
|
|
1541
|
-
return fs3.existsSync(
|
|
1567
|
+
return fs3.existsSync(path4.join(getAgentSkillPath(agent), "SKILL.md"));
|
|
1542
1568
|
}
|
|
1543
1569
|
function copyDirSync2(src, dest) {
|
|
1544
1570
|
fs3.mkdirSync(dest, { recursive: true });
|
|
1545
1571
|
for (const entry of fs3.readdirSync(src, { withFileTypes: true })) {
|
|
1546
|
-
const srcPath =
|
|
1547
|
-
const destPath =
|
|
1572
|
+
const srcPath = path4.join(src, entry.name);
|
|
1573
|
+
const destPath = path4.join(dest, entry.name);
|
|
1548
1574
|
if (entry.isDirectory()) {
|
|
1549
1575
|
copyDirSync2(srcPath, destPath);
|
|
1550
1576
|
} else {
|
|
@@ -1557,7 +1583,7 @@ function installSkillForAgents(agentIds) {
|
|
|
1557
1583
|
const canonical = getCanonicalSkillPath2();
|
|
1558
1584
|
const installed = [];
|
|
1559
1585
|
const failed = [];
|
|
1560
|
-
if (!fs3.existsSync(
|
|
1586
|
+
if (!fs3.existsSync(path4.join(source, "SKILL.md"))) {
|
|
1561
1587
|
return { installed: [], failed: ["skill source not found"] };
|
|
1562
1588
|
}
|
|
1563
1589
|
try {
|
|
@@ -1579,14 +1605,14 @@ function installSkillForAgents(agentIds) {
|
|
|
1579
1605
|
continue;
|
|
1580
1606
|
}
|
|
1581
1607
|
try {
|
|
1582
|
-
const agentSkillsDir =
|
|
1608
|
+
const agentSkillsDir = path4.dirname(agentPath);
|
|
1583
1609
|
fs3.mkdirSync(agentSkillsDir, { recursive: true });
|
|
1584
1610
|
try {
|
|
1585
1611
|
fs3.lstatSync(agentPath);
|
|
1586
1612
|
fs3.rmSync(agentPath, { recursive: true });
|
|
1587
1613
|
} catch {
|
|
1588
1614
|
}
|
|
1589
|
-
const relative =
|
|
1615
|
+
const relative = path4.relative(agentSkillsDir, canonical);
|
|
1590
1616
|
fs3.symlinkSync(relative, agentPath);
|
|
1591
1617
|
installed.push(agent.name);
|
|
1592
1618
|
seen.set(agentPath, true);
|
|
@@ -1833,7 +1859,7 @@ ${whoami.user.name} ${pc2.dim(`(${whoami.user.email})`)}`,
|
|
|
1833
1859
|
};
|
|
1834
1860
|
await promptConnectIntegrations(apiKey, connParams);
|
|
1835
1861
|
const savedPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
|
|
1836
|
-
const resolutionHint = scope === "project" ? `When you run ${pc2.cyan("one")} from ${pc2.bold(
|
|
1862
|
+
const resolutionHint = scope === "project" ? `When you run ${pc2.cyan("one")} from ${pc2.bold(path4.basename(getProjectRoot()))}, it uses this project config.
|
|
1837
1863
|
From anywhere else, it falls back to your global config.` : `This config applies to every folder unless a project config is set.`;
|
|
1838
1864
|
p3.note(
|
|
1839
1865
|
`${scopeLabel(scope)} Config saved to:
|
|
@@ -2523,11 +2549,11 @@ async function actionsSearchCommand(platform, query, options) {
|
|
|
2523
2549
|
const useCache = options.cache !== false;
|
|
2524
2550
|
const searchType = agentType || "knowledge";
|
|
2525
2551
|
const cachePath = searchCachePath(platform, query, searchType);
|
|
2526
|
-
const
|
|
2552
|
+
const cached2 = useCache ? readCache(cachePath) : null;
|
|
2527
2553
|
let cleanedActions;
|
|
2528
2554
|
let cacheHit = false;
|
|
2529
|
-
if (
|
|
2530
|
-
cleanedActions =
|
|
2555
|
+
if (cached2 && isFresh(cached2)) {
|
|
2556
|
+
cleanedActions = cached2.data.actions;
|
|
2531
2557
|
cacheHit = true;
|
|
2532
2558
|
} else {
|
|
2533
2559
|
try {
|
|
@@ -2535,12 +2561,12 @@ async function actionsSearchCommand(platform, query, options) {
|
|
|
2535
2561
|
platform,
|
|
2536
2562
|
query,
|
|
2537
2563
|
agentType,
|
|
2538
|
-
|
|
2564
|
+
cached2?.etag ?? void 0
|
|
2539
2565
|
);
|
|
2540
|
-
if (result.status === 304 &&
|
|
2541
|
-
|
|
2542
|
-
writeCache(cachePath,
|
|
2543
|
-
cleanedActions =
|
|
2566
|
+
if (result.status === 304 && cached2) {
|
|
2567
|
+
cached2.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2568
|
+
writeCache(cachePath, cached2);
|
|
2569
|
+
cleanedActions = cached2.data.actions;
|
|
2544
2570
|
cacheHit = true;
|
|
2545
2571
|
} else {
|
|
2546
2572
|
let actions2 = result.data;
|
|
@@ -2559,12 +2585,12 @@ async function actionsSearchCommand(platform, query, options) {
|
|
|
2559
2585
|
));
|
|
2560
2586
|
}
|
|
2561
2587
|
} catch (fetchError) {
|
|
2562
|
-
if (
|
|
2588
|
+
if (cached2) {
|
|
2563
2589
|
process.stderr.write(
|
|
2564
|
-
`Warning: serving cached search results (network unavailable, cached ${formatAge(getAge(
|
|
2590
|
+
`Warning: serving cached search results (network unavailable, cached ${formatAge(getAge(cached2))} ago)
|
|
2565
2591
|
`
|
|
2566
2592
|
);
|
|
2567
|
-
cleanedActions =
|
|
2593
|
+
cleanedActions = cached2.data.actions;
|
|
2568
2594
|
cacheHit = true;
|
|
2569
2595
|
} else {
|
|
2570
2596
|
throw fetchError;
|
|
@@ -2573,8 +2599,8 @@ async function actionsSearchCommand(platform, query, options) {
|
|
|
2573
2599
|
}
|
|
2574
2600
|
if (isAgentMode()) {
|
|
2575
2601
|
const response = { actions: cleanedActions };
|
|
2576
|
-
if (cacheHit &&
|
|
2577
|
-
response._cache = buildCacheMeta(
|
|
2602
|
+
if (cacheHit && cached2) {
|
|
2603
|
+
response._cache = buildCacheMeta(cached2, true);
|
|
2578
2604
|
} else {
|
|
2579
2605
|
const freshEntry = readCache(cachePath);
|
|
2580
2606
|
response._cache = buildCacheMeta(freshEntry, false);
|
|
@@ -3196,7 +3222,7 @@ import pc7 from "picocolors";
|
|
|
3196
3222
|
|
|
3197
3223
|
// src/lib/flow-validator.ts
|
|
3198
3224
|
import fs4 from "fs";
|
|
3199
|
-
import
|
|
3225
|
+
import path5 from "path";
|
|
3200
3226
|
import { spawnSync } from "child_process";
|
|
3201
3227
|
function validateFlowSchema(flow2) {
|
|
3202
3228
|
const errors = [];
|
|
@@ -3271,32 +3297,32 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3271
3297
|
const validTypes = FLOW_SCHEMA.stepTypes.map((st) => st.type);
|
|
3272
3298
|
for (let i = 0; i < steps.length; i++) {
|
|
3273
3299
|
const step = steps[i];
|
|
3274
|
-
const
|
|
3300
|
+
const path13 = `${pathPrefix}[${i}]`;
|
|
3275
3301
|
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
3276
|
-
errors.push({ path:
|
|
3302
|
+
errors.push({ path: path13, message: "Step must be an object" });
|
|
3277
3303
|
continue;
|
|
3278
3304
|
}
|
|
3279
3305
|
const s = step;
|
|
3280
3306
|
if (!s.id || typeof s.id !== "string") {
|
|
3281
|
-
errors.push({ path: `${
|
|
3307
|
+
errors.push({ path: `${path13}.id`, message: 'Step must have a string "id"' });
|
|
3282
3308
|
}
|
|
3283
3309
|
if (!s.name || typeof s.name !== "string") {
|
|
3284
|
-
errors.push({ path: `${
|
|
3310
|
+
errors.push({ path: `${path13}.name`, message: 'Step must have a string "name"' });
|
|
3285
3311
|
}
|
|
3286
3312
|
if (!s.type || !validTypes.includes(s.type)) {
|
|
3287
|
-
errors.push({ path: `${
|
|
3313
|
+
errors.push({ path: `${path13}.type`, message: `Step type must be one of: ${validTypes.join(", ")}` });
|
|
3288
3314
|
continue;
|
|
3289
3315
|
}
|
|
3290
3316
|
if (s.requires !== void 0) {
|
|
3291
3317
|
if (!Array.isArray(s.requires)) {
|
|
3292
|
-
errors.push({ path: `${
|
|
3318
|
+
errors.push({ path: `${path13}.requires`, message: '"requires" must be an array of selector strings (e.g. ["$.steps.foo.output.bar"])' });
|
|
3293
3319
|
} else {
|
|
3294
3320
|
for (let r = 0; r < s.requires.length; r++) {
|
|
3295
3321
|
const sel = s.requires[r];
|
|
3296
3322
|
if (typeof sel !== "string") {
|
|
3297
|
-
errors.push({ path: `${
|
|
3323
|
+
errors.push({ path: `${path13}.requires[${r}]`, message: '"requires" entry must be a selector string' });
|
|
3298
3324
|
} else if (!sel.startsWith("$.")) {
|
|
3299
|
-
errors.push({ path: `${
|
|
3325
|
+
errors.push({ path: `${path13}.requires[${r}]`, message: `"requires" entry "${sel}" must be a selector starting with "$." (e.g. "$.steps.foo.output.bar")` });
|
|
3300
3326
|
}
|
|
3301
3327
|
}
|
|
3302
3328
|
}
|
|
@@ -3304,7 +3330,7 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3304
3330
|
if (s.onError && typeof s.onError === "object") {
|
|
3305
3331
|
const oe = s.onError;
|
|
3306
3332
|
if (!FLOW_SCHEMA.errorStrategies.includes(oe.strategy)) {
|
|
3307
|
-
errors.push({ path: `${
|
|
3333
|
+
errors.push({ path: `${path13}.onError.strategy`, message: `Error strategy must be one of: ${FLOW_SCHEMA.errorStrategies.join(", ")}` });
|
|
3308
3334
|
}
|
|
3309
3335
|
}
|
|
3310
3336
|
const descriptor = getStepTypeDescriptor(s.type);
|
|
@@ -3314,14 +3340,14 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3314
3340
|
if (!configObj || typeof configObj !== "object") {
|
|
3315
3341
|
const hint = detectFlatConfigHint(s, descriptor);
|
|
3316
3342
|
errors.push({
|
|
3317
|
-
path: `${
|
|
3343
|
+
path: `${path13}.${configKey}`,
|
|
3318
3344
|
message: `${capitalize(descriptor.type)} step must have a "${configKey}" config object${hint}`
|
|
3319
3345
|
});
|
|
3320
3346
|
continue;
|
|
3321
3347
|
}
|
|
3322
3348
|
const config2 = configObj;
|
|
3323
3349
|
for (const [fieldName, fd] of Object.entries(descriptor.fields)) {
|
|
3324
|
-
const fieldPath = `${
|
|
3350
|
+
const fieldPath = `${path13}.${configKey}.${fieldName}`;
|
|
3325
3351
|
const value = config2[fieldName];
|
|
3326
3352
|
if (fd.required && (value === void 0 || value === null || value === "")) {
|
|
3327
3353
|
errors.push({ path: fieldPath, message: `${capitalize(descriptor.type)} must have ${fd.type === "string" ? "a string" : fd.type === "array" ? "a" : "a"} "${fieldName}"` });
|
|
@@ -3354,30 +3380,30 @@ function validateStepsArray(steps, pathPrefix, errors) {
|
|
|
3354
3380
|
}
|
|
3355
3381
|
}
|
|
3356
3382
|
if (descriptor.type === "action") {
|
|
3357
|
-
validateConnectionForm(config2, `${
|
|
3383
|
+
validateConnectionForm(config2, `${path13}.${configKey}`, errors);
|
|
3358
3384
|
}
|
|
3359
3385
|
if (descriptor.type === "code") {
|
|
3360
3386
|
const hasSource = typeof config2.source === "string" && config2.source.length > 0;
|
|
3361
3387
|
const hasModule = typeof config2.module === "string" && config2.module.length > 0;
|
|
3362
3388
|
if (!hasSource && !hasModule) {
|
|
3363
|
-
errors.push({ path: `${
|
|
3389
|
+
errors.push({ path: `${path13}.${configKey}`, message: 'Code step must define either "source" (inline JS) or "module" (path to .mjs file)' });
|
|
3364
3390
|
} else if (hasSource && hasModule) {
|
|
3365
|
-
errors.push({ path: `${
|
|
3391
|
+
errors.push({ path: `${path13}.${configKey}`, message: 'Code step cannot define both "source" and "module" \u2014 pick one' });
|
|
3366
3392
|
}
|
|
3367
3393
|
if (hasModule) {
|
|
3368
3394
|
const m = config2.module;
|
|
3369
3395
|
if (m.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(m)) {
|
|
3370
|
-
errors.push({ path: `${
|
|
3396
|
+
errors.push({ path: `${path13}.${configKey}.module`, message: "Code module path must be relative to the flow folder (no absolute paths)" });
|
|
3371
3397
|
} else if (m.split(/[\\/]/).includes("..")) {
|
|
3372
|
-
errors.push({ path: `${
|
|
3398
|
+
errors.push({ path: `${path13}.${configKey}.module`, message: 'Code module path must not escape the flow folder ("..")' });
|
|
3373
3399
|
} else if (!m.endsWith(".mjs")) {
|
|
3374
|
-
errors.push({ path: `${
|
|
3400
|
+
errors.push({ path: `${path13}.${configKey}.module`, message: "Code module must be a .mjs file" });
|
|
3375
3401
|
}
|
|
3376
3402
|
}
|
|
3377
3403
|
if (hasSource) {
|
|
3378
3404
|
const syntaxError = checkCodeSourceSyntax(config2.source);
|
|
3379
3405
|
if (syntaxError) {
|
|
3380
|
-
errors.push({ path: `${
|
|
3406
|
+
errors.push({ path: `${path13}.${configKey}.source`, message: `Syntax error in code step: ${syntaxError}` });
|
|
3381
3407
|
}
|
|
3382
3408
|
}
|
|
3383
3409
|
}
|
|
@@ -3449,16 +3475,16 @@ function validateStepIds(flow2) {
|
|
|
3449
3475
|
function collectIds(steps, pathPrefix) {
|
|
3450
3476
|
for (let i = 0; i < steps.length; i++) {
|
|
3451
3477
|
const step = steps[i];
|
|
3452
|
-
const
|
|
3478
|
+
const path13 = `${pathPrefix}[${i}]`;
|
|
3453
3479
|
if (seen.has(step.id)) {
|
|
3454
|
-
errors.push({ path: `${
|
|
3480
|
+
errors.push({ path: `${path13}.id`, message: `Duplicate step ID: "${step.id}"` });
|
|
3455
3481
|
} else {
|
|
3456
3482
|
seen.add(step.id);
|
|
3457
3483
|
}
|
|
3458
3484
|
for (const { configKey, fieldName } of nestedKeys) {
|
|
3459
3485
|
const config2 = step[configKey];
|
|
3460
3486
|
if (config2 && Array.isArray(config2[fieldName])) {
|
|
3461
|
-
collectIds(config2[fieldName], `${
|
|
3487
|
+
collectIds(config2[fieldName], `${path13}.${configKey}.${fieldName}`);
|
|
3462
3488
|
}
|
|
3463
3489
|
}
|
|
3464
3490
|
}
|
|
@@ -3506,7 +3532,7 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3506
3532
|
}
|
|
3507
3533
|
return selectors;
|
|
3508
3534
|
}
|
|
3509
|
-
function checkSelectors(selectors,
|
|
3535
|
+
function checkSelectors(selectors, path13, precedingStepIds) {
|
|
3510
3536
|
for (const selector of selectors) {
|
|
3511
3537
|
const parts = selector.split(".");
|
|
3512
3538
|
if (parts.length < 3) continue;
|
|
@@ -3514,15 +3540,15 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3514
3540
|
if (root === "input") {
|
|
3515
3541
|
const inputName = parts[2];
|
|
3516
3542
|
if (!inputNames.has(inputName)) {
|
|
3517
|
-
errors.push({ path:
|
|
3543
|
+
errors.push({ path: path13, message: `Selector "${selector}" references undefined input "${inputName}"` });
|
|
3518
3544
|
}
|
|
3519
3545
|
} else if (root === "steps") {
|
|
3520
3546
|
const stepId = parts[2].replace(/[\[\]]/g, "").split(/[\[\]]/)[0];
|
|
3521
3547
|
if (!allStepIds.has(stepId)) {
|
|
3522
|
-
errors.push({ path:
|
|
3548
|
+
errors.push({ path: path13, message: `Selector "${selector}" references undefined step "${stepId}"` });
|
|
3523
3549
|
} else if (precedingStepIds && !precedingStepIds.has(stepId)) {
|
|
3524
3550
|
errors.push({
|
|
3525
|
-
path:
|
|
3551
|
+
path: path13,
|
|
3526
3552
|
message: `Selector "${selector}" references step "${stepId}" which is declared after the current step. Steps execute in declaration order, so this will always resolve to undefined at runtime \u2014 move the dependency earlier in the steps array.`
|
|
3527
3553
|
});
|
|
3528
3554
|
}
|
|
@@ -3530,20 +3556,20 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3530
3556
|
}
|
|
3531
3557
|
}
|
|
3532
3558
|
const EXPRESSION_FIELDS = /* @__PURE__ */ new Set(["condition.expression", "while.condition"]);
|
|
3533
|
-
function checkOperatorsInSelectorField(value,
|
|
3559
|
+
function checkOperatorsInSelectorField(value, path13) {
|
|
3534
3560
|
if (typeof value === "string" && value.startsWith("$.")) {
|
|
3535
3561
|
if (value.includes("||")) {
|
|
3536
|
-
errors.push({ path:
|
|
3562
|
+
errors.push({ path: path13, message: `Selector "${value}" contains unsupported operator "||". Selectors in data fields use dot-path resolution, not JS evaluation. Use the "default" field on the input definition instead, or use a "code" step for complex expressions.` });
|
|
3537
3563
|
} else if (value.includes("&&")) {
|
|
3538
|
-
errors.push({ path:
|
|
3564
|
+
errors.push({ path: path13, message: `Selector "${value}" contains unsupported operator "&&". Selectors in data fields use dot-path resolution, not JS evaluation. Use a "condition" step or "code" step for complex expressions.` });
|
|
3539
3565
|
}
|
|
3540
3566
|
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
3541
3567
|
for (const [k, v] of Object.entries(value)) {
|
|
3542
|
-
checkOperatorsInSelectorField(v, `${
|
|
3568
|
+
checkOperatorsInSelectorField(v, `${path13}.${k}`);
|
|
3543
3569
|
}
|
|
3544
3570
|
} else if (Array.isArray(value)) {
|
|
3545
3571
|
for (let i = 0; i < value.length; i++) {
|
|
3546
|
-
checkOperatorsInSelectorField(value[i], `${
|
|
3572
|
+
checkOperatorsInSelectorField(value[i], `${path13}[${i}]`);
|
|
3547
3573
|
}
|
|
3548
3574
|
}
|
|
3549
3575
|
}
|
|
@@ -3587,7 +3613,7 @@ function validateSelectorReferences(flow2, rootDir) {
|
|
|
3587
3613
|
}
|
|
3588
3614
|
const modulePath = step.type === "code" ? c.module : void 0;
|
|
3589
3615
|
if (rootDir && typeof modulePath === "string" && modulePath.length > 0) {
|
|
3590
|
-
const abs =
|
|
3616
|
+
const abs = path5.resolve(rootDir, modulePath);
|
|
3591
3617
|
if (fs4.existsSync(abs)) {
|
|
3592
3618
|
try {
|
|
3593
3619
|
const moduleText = fs4.readFileSync(abs, "utf-8");
|
|
@@ -3628,10 +3654,10 @@ var VALID_OUTPUT_SCHEMA_TYPES = /* @__PURE__ */ new Set(["string", "number", "bo
|
|
|
3628
3654
|
function isOutputSchemaObject(v) {
|
|
3629
3655
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
3630
3656
|
}
|
|
3631
|
-
function walkOutputSchema(schema,
|
|
3657
|
+
function walkOutputSchema(schema, path13) {
|
|
3632
3658
|
let current = schema;
|
|
3633
|
-
for (let i = 0; i <
|
|
3634
|
-
const seg =
|
|
3659
|
+
for (let i = 0; i < path13.length; i++) {
|
|
3660
|
+
const seg = path13[i];
|
|
3635
3661
|
if (typeof current === "string") {
|
|
3636
3662
|
return current === "unknown" || current === "object" || current === "array" ? "opaque" : "opaque";
|
|
3637
3663
|
}
|
|
@@ -3783,7 +3809,7 @@ function validateCodeModules(flow2, rootDir) {
|
|
|
3783
3809
|
const stepPath = `${pathPrefix}[${i}]`;
|
|
3784
3810
|
if (step.type === "code" && step.code?.module) {
|
|
3785
3811
|
const m = step.code.module;
|
|
3786
|
-
const abs =
|
|
3812
|
+
const abs = path5.resolve(rootDir, m);
|
|
3787
3813
|
if (!fs4.existsSync(abs)) {
|
|
3788
3814
|
errors.push({
|
|
3789
3815
|
path: `${stepPath}.code.module`,
|
|
@@ -3916,9 +3942,9 @@ function validateFileReadSchemas(flow2) {
|
|
|
3916
3942
|
|
|
3917
3943
|
// src/commands/flow.ts
|
|
3918
3944
|
import fs5 from "fs";
|
|
3919
|
-
import
|
|
3945
|
+
import path6 from "path";
|
|
3920
3946
|
async function writeFlowResultFile(filePath, meta, steps) {
|
|
3921
|
-
const abs =
|
|
3947
|
+
const abs = path6.resolve(filePath);
|
|
3922
3948
|
const ws = fs5.createWriteStream(abs);
|
|
3923
3949
|
const done = new Promise((resolve, reject) => {
|
|
3924
3950
|
ws.on("finish", () => resolve());
|
|
@@ -4326,7 +4352,7 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
4326
4352
|
const flowPath = resolveFlowPath(keyOrPath);
|
|
4327
4353
|
const content = fs5.readFileSync(flowPath, "utf-8");
|
|
4328
4354
|
flowData = JSON.parse(content);
|
|
4329
|
-
rootDir =
|
|
4355
|
+
rootDir = path6.dirname(flowPath);
|
|
4330
4356
|
}
|
|
4331
4357
|
} catch (err) {
|
|
4332
4358
|
spinner5.stop("Validation failed");
|
|
@@ -4353,7 +4379,7 @@ async function flowValidateCommand(keyOrPath) {
|
|
|
4353
4379
|
}
|
|
4354
4380
|
note(`Workflow "${flowData.key}" passed all validation checks`, "Valid");
|
|
4355
4381
|
}
|
|
4356
|
-
async function flowResumeCommand(runId) {
|
|
4382
|
+
async function flowResumeCommand(runId, options = {}) {
|
|
4357
4383
|
intro(pc7.bgCyan(pc7.black(" One Workflow ")));
|
|
4358
4384
|
const state = FlowRunner.loadRunState(runId);
|
|
4359
4385
|
if (!state) {
|
|
@@ -4374,6 +4400,14 @@ async function flowResumeCommand(runId) {
|
|
|
4374
4400
|
error(`Could not load workflow "${state.flowKey}": ${err instanceof Error ? err.message : String(err)}`);
|
|
4375
4401
|
return;
|
|
4376
4402
|
}
|
|
4403
|
+
if (!options.allowBash && flowRequiresBash(flow2)) {
|
|
4404
|
+
const msg = `Workflow "${flow2.key}" contains bash steps. Re-run with --allow-bash to permit shell execution.`;
|
|
4405
|
+
if (isAgentMode()) {
|
|
4406
|
+
json({ error: msg, requiresBash: true, flowKey: flow2.key, runId });
|
|
4407
|
+
process.exit(1);
|
|
4408
|
+
}
|
|
4409
|
+
error(msg);
|
|
4410
|
+
}
|
|
4377
4411
|
const runner = FlowRunner.fromRunState(state);
|
|
4378
4412
|
const onEvent = (event) => {
|
|
4379
4413
|
if (isAgentMode()) {
|
|
@@ -4383,7 +4417,11 @@ async function flowResumeCommand(runId) {
|
|
|
4383
4417
|
const spinner5 = createSpinner();
|
|
4384
4418
|
spinner5.start(`Resuming run ${runId} (${state.completedSteps.length} steps already completed)...`);
|
|
4385
4419
|
try {
|
|
4386
|
-
const context = await runner.resume(flow2, api, permissions, actionIds, {
|
|
4420
|
+
const context = await runner.resume(flow2, api, permissions, actionIds, {
|
|
4421
|
+
onEvent,
|
|
4422
|
+
rootDir,
|
|
4423
|
+
allowBash: options.allowBash
|
|
4424
|
+
});
|
|
4387
4425
|
spinner5.stop("Workflow completed");
|
|
4388
4426
|
if (isAgentMode()) {
|
|
4389
4427
|
json({
|
|
@@ -4502,7 +4540,7 @@ async function flowInspectCommand(runId, options = {}) {
|
|
|
4502
4540
|
}
|
|
4503
4541
|
console.log();
|
|
4504
4542
|
console.log(` ${pc7.dim(`State: ${statePath}`)}`);
|
|
4505
|
-
console.log(` ${pc7.dim(`Log: ${
|
|
4543
|
+
console.log(` ${pc7.dim(`Log: ${path6.join(".one/flows/.logs", `${state.flowKey}-${state.runId}.log`)}`)}`);
|
|
4506
4544
|
console.log();
|
|
4507
4545
|
}
|
|
4508
4546
|
function colorStatus(status) {
|
|
@@ -5208,10 +5246,10 @@ function handleId(response, config2, records) {
|
|
|
5208
5246
|
|
|
5209
5247
|
// src/lib/memory/sync/state.ts
|
|
5210
5248
|
import fs6 from "fs";
|
|
5211
|
-
import
|
|
5212
|
-
var SYNC_DIR =
|
|
5213
|
-
var STATE_DIR =
|
|
5214
|
-
var LEGACY_SINGLE_FILE =
|
|
5249
|
+
import path7 from "path";
|
|
5250
|
+
var SYNC_DIR = path7.join(".one", "sync");
|
|
5251
|
+
var STATE_DIR = path7.join(SYNC_DIR, "state");
|
|
5252
|
+
var LEGACY_SINGLE_FILE = path7.join(SYNC_DIR, "sync_state.json");
|
|
5215
5253
|
var legacyMigrationDone = false;
|
|
5216
5254
|
function rowToState(row) {
|
|
5217
5255
|
return {
|
|
@@ -5264,7 +5302,7 @@ async function migrateLegacyOnce() {
|
|
|
5264
5302
|
const backend = await getBackend();
|
|
5265
5303
|
const platforms = fs6.readdirSync(STATE_DIR);
|
|
5266
5304
|
for (const platform of platforms) {
|
|
5267
|
-
const platformDir =
|
|
5305
|
+
const platformDir = path7.join(STATE_DIR, platform);
|
|
5268
5306
|
let entries;
|
|
5269
5307
|
try {
|
|
5270
5308
|
entries = fs6.readdirSync(platformDir);
|
|
@@ -5274,7 +5312,7 @@ async function migrateLegacyOnce() {
|
|
|
5274
5312
|
for (const entry of entries) {
|
|
5275
5313
|
if (!entry.endsWith(".json")) continue;
|
|
5276
5314
|
const model = entry.slice(0, -".json".length);
|
|
5277
|
-
const filePath =
|
|
5315
|
+
const filePath = path7.join(platformDir, entry);
|
|
5278
5316
|
try {
|
|
5279
5317
|
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
5280
5318
|
const modelState = JSON.parse(raw);
|
|
@@ -5331,11 +5369,11 @@ async function removeModelState(platform, model) {
|
|
|
5331
5369
|
|
|
5332
5370
|
// src/lib/memory/sync/lock.ts
|
|
5333
5371
|
import fs7 from "fs";
|
|
5334
|
-
import
|
|
5335
|
-
var LOCK_DIR_REL =
|
|
5372
|
+
import path8 from "path";
|
|
5373
|
+
var LOCK_DIR_REL = path8.join(".one", "sync", "locks");
|
|
5336
5374
|
var STALE_MS = 30 * 60 * 1e3;
|
|
5337
5375
|
function lockPath(platform, model) {
|
|
5338
|
-
return
|
|
5376
|
+
return path8.join(LOCK_DIR_REL, `${platform}_${model}`);
|
|
5339
5377
|
}
|
|
5340
5378
|
function isProcessAlive(pid) {
|
|
5341
5379
|
try {
|
|
@@ -5354,7 +5392,7 @@ var SyncLockError = class extends Error {
|
|
|
5354
5392
|
function acquireSyncLock(platform, model) {
|
|
5355
5393
|
fs7.mkdirSync(LOCK_DIR_REL, { recursive: true });
|
|
5356
5394
|
const dir = lockPath(platform, model);
|
|
5357
|
-
const pidFile =
|
|
5395
|
+
const pidFile = path8.join(dir, "pid");
|
|
5358
5396
|
try {
|
|
5359
5397
|
fs7.mkdirSync(dir);
|
|
5360
5398
|
} catch (err) {
|
|
@@ -5412,8 +5450,8 @@ function acquireSyncLock(platform, model) {
|
|
|
5412
5450
|
// src/lib/memory/sync/hooks.ts
|
|
5413
5451
|
import { spawn as spawn2 } from "child_process";
|
|
5414
5452
|
import fs8 from "fs";
|
|
5415
|
-
import
|
|
5416
|
-
var EVENTS_DIR =
|
|
5453
|
+
import path9 from "path";
|
|
5454
|
+
var EVENTS_DIR = path9.join(".one", "sync", "events");
|
|
5417
5455
|
function classifyRecords(db, model, records, idField, tableExists2) {
|
|
5418
5456
|
if (!tableExists2 || records.length === 0) {
|
|
5419
5457
|
return { inserts: records, updates: [] };
|
|
@@ -5460,7 +5498,7 @@ function appendEventLog(events) {
|
|
|
5460
5498
|
if (events.length === 0) return;
|
|
5461
5499
|
const { platform, model } = events[0];
|
|
5462
5500
|
fs8.mkdirSync(EVENTS_DIR, { recursive: true });
|
|
5463
|
-
const logPath =
|
|
5501
|
+
const logPath = path9.join(EVENTS_DIR, `${platform}_${model}.jsonl`);
|
|
5464
5502
|
const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
5465
5503
|
fs8.appendFileSync(logPath, lines);
|
|
5466
5504
|
}
|
|
@@ -5566,8 +5604,8 @@ function sleep(ms) {
|
|
|
5566
5604
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5567
5605
|
}
|
|
5568
5606
|
function interpolate(template, record) {
|
|
5569
|
-
return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_,
|
|
5570
|
-
const parts =
|
|
5607
|
+
return template.replace(/\{?\{(\w+(?:\.\w+)*)\}\}?/g, (_, path13) => {
|
|
5608
|
+
const parts = path13.split(".");
|
|
5571
5609
|
let value = record;
|
|
5572
5610
|
for (const part of parts) {
|
|
5573
5611
|
if (typeof value !== "object" || value === null) return "";
|
|
@@ -5595,8 +5633,8 @@ function deepMerge(target, source) {
|
|
|
5595
5633
|
}
|
|
5596
5634
|
return result;
|
|
5597
5635
|
}
|
|
5598
|
-
function getByDotPath2(obj,
|
|
5599
|
-
const parts =
|
|
5636
|
+
function getByDotPath2(obj, path13) {
|
|
5637
|
+
const parts = path13.split(".");
|
|
5600
5638
|
let current = obj;
|
|
5601
5639
|
for (const part of parts) {
|
|
5602
5640
|
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
@@ -5605,8 +5643,8 @@ function getByDotPath2(obj, path12) {
|
|
|
5605
5643
|
return current;
|
|
5606
5644
|
}
|
|
5607
5645
|
function stripExcludedFields(obj, paths) {
|
|
5608
|
-
for (const
|
|
5609
|
-
stripOnePath(obj,
|
|
5646
|
+
for (const path13 of paths) {
|
|
5647
|
+
stripOnePath(obj, path13.replace(/\[\]/g, ".*").split("."));
|
|
5610
5648
|
}
|
|
5611
5649
|
}
|
|
5612
5650
|
function stripOnePath(obj, parts) {
|
|
@@ -6027,8 +6065,8 @@ function sleep2(ms) {
|
|
|
6027
6065
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6028
6066
|
}
|
|
6029
6067
|
function stripFields(record, paths) {
|
|
6030
|
-
for (const
|
|
6031
|
-
stripOnePath2(record,
|
|
6068
|
+
for (const path13 of paths) {
|
|
6069
|
+
stripOnePath2(record, path13.split("."));
|
|
6032
6070
|
}
|
|
6033
6071
|
}
|
|
6034
6072
|
function stripOnePath2(obj, parts) {
|
|
@@ -7123,13 +7161,13 @@ function inferProfileFromKnowledge(knowledge, modelName, platform) {
|
|
|
7123
7161
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7124
7162
|
import fs10 from "fs";
|
|
7125
7163
|
import os from "os";
|
|
7126
|
-
import
|
|
7164
|
+
import path11 from "path";
|
|
7127
7165
|
|
|
7128
7166
|
// src/lib/memory/sync/schedule-registry.ts
|
|
7129
7167
|
import fs9 from "fs";
|
|
7130
|
-
import
|
|
7131
|
-
var REGISTRY_DIR = () =>
|
|
7132
|
-
var REGISTRY_FILE = () =>
|
|
7168
|
+
import path10 from "path";
|
|
7169
|
+
var REGISTRY_DIR = () => path10.join(homeDir(), ".one", "sync");
|
|
7170
|
+
var REGISTRY_FILE = () => path10.join(REGISTRY_DIR(), "schedules.json");
|
|
7133
7171
|
function readRaw() {
|
|
7134
7172
|
try {
|
|
7135
7173
|
if (!fs9.existsSync(REGISTRY_FILE())) return { schedules: [] };
|
|
@@ -7148,7 +7186,7 @@ function writeRaw(file) {
|
|
|
7148
7186
|
fs9.renameSync(tmp, REGISTRY_FILE());
|
|
7149
7187
|
}
|
|
7150
7188
|
function makeScheduleId(platform, cwd) {
|
|
7151
|
-
const slug =
|
|
7189
|
+
const slug = path10.basename(cwd).replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
|
|
7152
7190
|
return `${platform}-${slug}`;
|
|
7153
7191
|
}
|
|
7154
7192
|
function listRegistered() {
|
|
@@ -7182,7 +7220,7 @@ function removeRegistered(id) {
|
|
|
7182
7220
|
|
|
7183
7221
|
// src/lib/memory/sync/schedule.ts
|
|
7184
7222
|
var MARKER = "# one-sync";
|
|
7185
|
-
var LOG_DIR_REL =
|
|
7223
|
+
var LOG_DIR_REL = path11.join(".one", "sync", "logs");
|
|
7186
7224
|
function durationToCron(every) {
|
|
7187
7225
|
const match = every.match(/^(\d+)([mhd])$/);
|
|
7188
7226
|
if (!match) return null;
|
|
@@ -7299,7 +7337,7 @@ function migrateLegacyCronEntries() {
|
|
|
7299
7337
|
const modelsMatch = command.match(/--models\s+(\S+)/);
|
|
7300
7338
|
const models = modelsMatch ? modelsMatch[1].split(",") : void 0;
|
|
7301
7339
|
const logMatch = command.match(/>>\s+"([^"]+)"/);
|
|
7302
|
-
const logFile = logMatch ? logMatch[1] :
|
|
7340
|
+
const logFile = logMatch ? logMatch[1] : path11.resolve(cwd, LOG_DIR_REL, `${platform}.log`);
|
|
7303
7341
|
const id = makeScheduleId(platform, cwd);
|
|
7304
7342
|
if (registeredIds.has(id)) continue;
|
|
7305
7343
|
upsertRegistered({
|
|
@@ -7333,9 +7371,9 @@ function addSchedule(opts) {
|
|
|
7333
7371
|
const cwd = process.cwd();
|
|
7334
7372
|
const id = makeScheduleId(opts.platform, cwd);
|
|
7335
7373
|
const replaced = getRegistered(id) !== void 0;
|
|
7336
|
-
const logDir =
|
|
7374
|
+
const logDir = path11.join(cwd, LOG_DIR_REL);
|
|
7337
7375
|
fs10.mkdirSync(logDir, { recursive: true });
|
|
7338
|
-
const logFile =
|
|
7376
|
+
const logFile = path11.join(logDir, `${opts.platform}.log`);
|
|
7339
7377
|
const entry = {
|
|
7340
7378
|
id,
|
|
7341
7379
|
platform: opts.platform,
|
|
@@ -7679,11 +7717,11 @@ function isNoise(s) {
|
|
|
7679
7717
|
if (/^-?\d+(\.\d+)?([eE][-+]?\d+)?$/.test(s)) return true;
|
|
7680
7718
|
return false;
|
|
7681
7719
|
}
|
|
7682
|
-
function recordSample(stats,
|
|
7683
|
-
let s = stats.get(
|
|
7720
|
+
function recordSample(stats, path13, value, jsType, recordIndex, totalSamples) {
|
|
7721
|
+
let s = stats.get(path13);
|
|
7684
7722
|
if (!s) {
|
|
7685
7723
|
s = {
|
|
7686
|
-
path:
|
|
7724
|
+
path: path13,
|
|
7687
7725
|
total: totalSamples,
|
|
7688
7726
|
recordIndices: /* @__PURE__ */ new Set(),
|
|
7689
7727
|
lenSum: 0,
|
|
@@ -7692,7 +7730,7 @@ function recordSample(stats, path12, value, jsType, recordIndex, totalSamples) {
|
|
|
7692
7730
|
primaryType: jsType,
|
|
7693
7731
|
examples: []
|
|
7694
7732
|
};
|
|
7695
|
-
stats.set(
|
|
7733
|
+
stats.set(path13, s);
|
|
7696
7734
|
}
|
|
7697
7735
|
s.recordIndices.add(recordIndex);
|
|
7698
7736
|
s.lenSum += value.length;
|
|
@@ -7701,28 +7739,28 @@ function recordSample(stats, path12, value, jsType, recordIndex, totalSamples) {
|
|
|
7701
7739
|
if (s.primaryType !== jsType) s.primaryType = "mixed";
|
|
7702
7740
|
if (s.examples.length < 3 && value.length < 200) s.examples.push(value);
|
|
7703
7741
|
}
|
|
7704
|
-
function walkRecord(record,
|
|
7742
|
+
function walkRecord(record, path13, stats, recordIndex, totalSamples) {
|
|
7705
7743
|
if (record === null || record === void 0) return;
|
|
7706
7744
|
if (typeof record === "string") {
|
|
7707
7745
|
const trimmed = record.trim();
|
|
7708
|
-
if (trimmed) recordSample(stats,
|
|
7746
|
+
if (trimmed) recordSample(stats, path13, trimmed, "string", recordIndex, totalSamples);
|
|
7709
7747
|
return;
|
|
7710
7748
|
}
|
|
7711
7749
|
if (typeof record === "number" || typeof record === "boolean") {
|
|
7712
7750
|
const str = String(record);
|
|
7713
7751
|
const kind = typeof record === "number" ? "number" : "boolean";
|
|
7714
|
-
if (str) recordSample(stats,
|
|
7752
|
+
if (str) recordSample(stats, path13, str, kind, recordIndex, totalSamples);
|
|
7715
7753
|
return;
|
|
7716
7754
|
}
|
|
7717
7755
|
if (Array.isArray(record)) {
|
|
7718
|
-
const childPath =
|
|
7756
|
+
const childPath = path13 ? `${path13}[]` : "[]";
|
|
7719
7757
|
for (const item of record) walkRecord(item, childPath, stats, recordIndex, totalSamples);
|
|
7720
7758
|
return;
|
|
7721
7759
|
}
|
|
7722
7760
|
if (typeof record === "object") {
|
|
7723
7761
|
for (const [key, value] of Object.entries(record)) {
|
|
7724
7762
|
if (key.startsWith("_")) continue;
|
|
7725
|
-
const childPath =
|
|
7763
|
+
const childPath = path13 ? `${path13}.${key}` : key;
|
|
7726
7764
|
walkRecord(value, childPath, stats, recordIndex, totalSamples);
|
|
7727
7765
|
}
|
|
7728
7766
|
}
|
|
@@ -8157,7 +8195,7 @@ function buildSearchablePreview(profile, samples) {
|
|
|
8157
8195
|
const first = samples[0];
|
|
8158
8196
|
const paths = getSearchablePaths(profile);
|
|
8159
8197
|
if (paths) {
|
|
8160
|
-
const perPathAgg = paths.map((
|
|
8198
|
+
const perPathAgg = paths.map((path13) => ({ path: path13, hits: 0, total: samples.length, sample: "" }));
|
|
8161
8199
|
for (const record of samples) {
|
|
8162
8200
|
const { paths: perPath } = extractSearchableFromPaths(record, paths);
|
|
8163
8201
|
perPath.forEach((p10, i) => {
|
|
@@ -9114,16 +9152,16 @@ function projectEmbeddingApiKey(cfg) {
|
|
|
9114
9152
|
}
|
|
9115
9153
|
function redactSecrets(cfg) {
|
|
9116
9154
|
const copy = JSON.parse(JSON.stringify(cfg));
|
|
9117
|
-
for (const
|
|
9118
|
-
const val = getPath(copy,
|
|
9155
|
+
for (const path13 of SECRET_PATHS) {
|
|
9156
|
+
const val = getPath(copy, path13);
|
|
9119
9157
|
if (typeof val === "string" && val.length > 0) {
|
|
9120
|
-
setPath(copy,
|
|
9158
|
+
setPath(copy, path13, `${val.slice(0, 6)}\u2026(redacted, use --show-secrets)`);
|
|
9121
9159
|
}
|
|
9122
9160
|
}
|
|
9123
9161
|
return copy;
|
|
9124
9162
|
}
|
|
9125
|
-
function getPath(obj,
|
|
9126
|
-
const parts =
|
|
9163
|
+
function getPath(obj, path13) {
|
|
9164
|
+
const parts = path13.split(".");
|
|
9127
9165
|
let cur = obj;
|
|
9128
9166
|
for (const part of parts) {
|
|
9129
9167
|
if (cur == null || typeof cur !== "object") return void 0;
|
|
@@ -9131,8 +9169,8 @@ function getPath(obj, path12) {
|
|
|
9131
9169
|
}
|
|
9132
9170
|
return cur;
|
|
9133
9171
|
}
|
|
9134
|
-
function setPath(obj,
|
|
9135
|
-
const parts =
|
|
9172
|
+
function setPath(obj, path13, value) {
|
|
9173
|
+
const parts = path13.split(".");
|
|
9136
9174
|
let cur = obj;
|
|
9137
9175
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9138
9176
|
const part = parts[i];
|
|
@@ -9142,8 +9180,8 @@ function setPath(obj, path12, value) {
|
|
|
9142
9180
|
cur[parts[parts.length - 1]] = value;
|
|
9143
9181
|
return obj;
|
|
9144
9182
|
}
|
|
9145
|
-
function unsetPath(obj,
|
|
9146
|
-
const parts =
|
|
9183
|
+
function unsetPath(obj, path13) {
|
|
9184
|
+
const parts = path13.split(".");
|
|
9147
9185
|
let cur = obj;
|
|
9148
9186
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9149
9187
|
const part = parts[i];
|
|
@@ -11634,13 +11672,6 @@ function posthogHost() {
|
|
|
11634
11672
|
function posthogKey() {
|
|
11635
11673
|
return process.env.ONE_POSTHOG_KEY || DEFAULT_POSTHOG_KEY;
|
|
11636
11674
|
}
|
|
11637
|
-
function cliVersion() {
|
|
11638
|
-
try {
|
|
11639
|
-
return require3("../package.json").version;
|
|
11640
|
-
} catch {
|
|
11641
|
-
return "unknown";
|
|
11642
|
-
}
|
|
11643
|
-
}
|
|
11644
11675
|
function envName() {
|
|
11645
11676
|
const key = getApiKey();
|
|
11646
11677
|
return key ? getEnvFromApiKey(key) : "live";
|
|
@@ -12113,11 +12144,11 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12113
12144
|
const configContent = fs13.readFileSync(resolved.path, "utf-8");
|
|
12114
12145
|
fs13.unlinkSync(resolved.path);
|
|
12115
12146
|
const next = resolveConfig();
|
|
12116
|
-
fs13.mkdirSync(
|
|
12147
|
+
fs13.mkdirSync(path12.dirname(resolved.path), { recursive: true });
|
|
12117
12148
|
fs13.writeFileSync(resolved.path, configContent);
|
|
12118
12149
|
let fallbackLabel;
|
|
12119
12150
|
if (next.scope === "project") {
|
|
12120
|
-
fallbackLabel = `parent project config (${
|
|
12151
|
+
fallbackLabel = `parent project config (${path12.basename(next.projectRoot)})`;
|
|
12121
12152
|
} else if (next.scope === "global") {
|
|
12122
12153
|
fallbackLabel = "global config";
|
|
12123
12154
|
} else {
|
|
@@ -12126,7 +12157,7 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12126
12157
|
if (!isAgentMode()) {
|
|
12127
12158
|
const p10 = await import("@clack/prompts");
|
|
12128
12159
|
const confirmed = await p10.confirm({
|
|
12129
|
-
message: `Delete project config for ${
|
|
12160
|
+
message: `Delete project config for ${path12.basename(resolved.projectRoot)}? Will fall back to ${fallbackLabel}.`,
|
|
12130
12161
|
initialValue: false
|
|
12131
12162
|
});
|
|
12132
12163
|
if (p10.isCancel(confirmed) || !confirmed) {
|
|
@@ -12136,7 +12167,7 @@ config.command("reset").description("Remove the project config for the current d
|
|
|
12136
12167
|
}
|
|
12137
12168
|
fs13.unlinkSync(resolved.path);
|
|
12138
12169
|
try {
|
|
12139
|
-
fs13.rmdirSync(
|
|
12170
|
+
fs13.rmdirSync(path12.dirname(resolved.path));
|
|
12140
12171
|
} catch {
|
|
12141
12172
|
}
|
|
12142
12173
|
if (isAgentMode()) {
|
|
@@ -12200,8 +12231,8 @@ flow.command("list").alias("ls").description("List all workflows in .one/flows/"
|
|
|
12200
12231
|
flow.command("validate <keyOrPath>").description("Validate a workflow JSON file").action(async (keyOrPath) => {
|
|
12201
12232
|
await flowValidateCommand(keyOrPath);
|
|
12202
12233
|
});
|
|
12203
|
-
flow.command("resume <runId>").description("Resume a paused or failed workflow run").action(async (runId) => {
|
|
12204
|
-
await flowResumeCommand(runId);
|
|
12234
|
+
flow.command("resume <runId>").description("Resume a paused or failed workflow run").option("--allow-bash", "Allow bash step execution (disabled by default for security) \u2014 required to resume any flow containing bash steps").action(async (runId, options) => {
|
|
12235
|
+
await flowResumeCommand(runId, options);
|
|
12205
12236
|
});
|
|
12206
12237
|
flow.command("runs [flowKey]").description("List workflow runs (optionally filtered by flow key)").action(async (flowKey) => {
|
|
12207
12238
|
await flowRunsCommand(flowKey);
|
package/package.json
CHANGED
|
@@ -686,8 +686,14 @@ one --agent flow execute <key> --allow-bash -i key=value
|
|
|
686
686
|
one --agent flow runs [flowKey]
|
|
687
687
|
one --agent flow inspect <runId> # per-step outputs of a past run (add --full for untruncated)
|
|
688
688
|
one --agent flow resume <runId>
|
|
689
|
+
one --agent flow resume <runId> --allow-bash # required if the flow has bash steps
|
|
689
690
|
```
|
|
690
691
|
|
|
692
|
+
`flow resume` gates bash exactly like `flow execute` — the permission is not
|
|
693
|
+
inherited from the original run. Resuming a bash flow without the flag fails
|
|
694
|
+
fast with `{"error": "...", "requiresBash": true, "flowKey": "...", "runId": "..."}`,
|
|
695
|
+
so re-invoke with `--allow-bash` rather than treating it as a broken run.
|
|
696
|
+
|
|
691
697
|
## Debugging a flow
|
|
692
698
|
|
|
693
699
|
Three tools that turn "re-run the whole 40-step flow to debug step 30" into near-zero-cost inspection:
|