@tablation/crew 0.43.1 → 0.43.2
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/dist/cli.js +85 -22
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7325,6 +7325,12 @@ async function fetchLatestHistoryId(route, agentsModelId, recordId, userAgent) {
|
|
|
7325
7325
|
function promptSourceFields(model, prompt) {
|
|
7326
7326
|
return model.fields?.some((f) => f.columnName === "prompt_baseline") ? { prompt_source: "crew", prompt_baseline: prompt } : {};
|
|
7327
7327
|
}
|
|
7328
|
+
function hasPromptBaselineColumn(model) {
|
|
7329
|
+
return model.fields?.some((f) => f.columnName === "prompt_baseline") === true;
|
|
7330
|
+
}
|
|
7331
|
+
function needsBaselineBackfill(model, row) {
|
|
7332
|
+
return hasPromptBaselineColumn(model) && row.prompt_customized !== true && (typeof row.prompt_baseline !== "string" || !row.prompt_source);
|
|
7333
|
+
}
|
|
7328
7334
|
function isPromptGateRejection(e) {
|
|
7329
7335
|
return e instanceof TablationApiError && e.status === 422;
|
|
7330
7336
|
}
|
|
@@ -7369,8 +7375,16 @@ async function syncPersonas(route, opts) {
|
|
|
7369
7375
|
continue;
|
|
7370
7376
|
}
|
|
7371
7377
|
if (row.prompt === defaultPrompt) {
|
|
7378
|
+
let anchoredAt = row.updated_at;
|
|
7379
|
+
if (!opts.dryRun && needsBaselineBackfill(agentsModel, row)) {
|
|
7380
|
+
try {
|
|
7381
|
+
anchoredAt = (await client2.records.update(agentsModel.id, row.id, promptSourceFields(agentsModel, defaultPrompt), row.updated_at)).updated_at;
|
|
7382
|
+
} catch (e) {
|
|
7383
|
+
if (!(e instanceof StaleWriteError6) && !isPromptGateRejection(e)) throw e;
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7372
7386
|
const historyId = await fetchLatestHistoryId(route, agentsModel.id, row.id, opts.userAgent);
|
|
7373
|
-
agentPersonas[role] = { agentId: row.id, lastSyncedUpdatedAt:
|
|
7387
|
+
agentPersonas[role] = { agentId: row.id, lastSyncedUpdatedAt: anchoredAt, ...historyId ? { historyId } : {} };
|
|
7374
7388
|
outcomes.push({ role, action: "unchanged", agentId: row.id });
|
|
7375
7389
|
continue;
|
|
7376
7390
|
}
|
|
@@ -7400,20 +7414,28 @@ async function syncPersonas(route, opts) {
|
|
|
7400
7414
|
continue;
|
|
7401
7415
|
}
|
|
7402
7416
|
const cached = cache[role]?.agentId === row.id ? cache[role] : void 0;
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
+
const baselineKnown = hasPromptBaselineColumn(agentsModel) && typeof row.prompt_baseline === "string";
|
|
7418
|
+
if (baselineKnown) {
|
|
7419
|
+
if (row.prompt !== row.prompt_baseline) {
|
|
7420
|
+
outcomes.push({ role, action: "diverged", agentId: row.id });
|
|
7421
|
+
continue;
|
|
7422
|
+
}
|
|
7423
|
+
} else {
|
|
7424
|
+
if (!cached?.historyId) {
|
|
7425
|
+
outcomes.push({ role, action: "diverged", agentId: row.id });
|
|
7426
|
+
continue;
|
|
7427
|
+
}
|
|
7428
|
+
let lastSyncedPrompt;
|
|
7429
|
+
try {
|
|
7430
|
+
const entries = await fetchHistoryEntries(route, agentsModel.id, row.id, opts.userAgent);
|
|
7431
|
+
lastSyncedPrompt = entries.find((e) => e.history_id === cached.historyId)?.prompt;
|
|
7432
|
+
} catch {
|
|
7433
|
+
lastSyncedPrompt = void 0;
|
|
7434
|
+
}
|
|
7435
|
+
if (lastSyncedPrompt === void 0 || lastSyncedPrompt !== row.prompt) {
|
|
7436
|
+
outcomes.push({ role, action: "diverged", agentId: row.id });
|
|
7437
|
+
continue;
|
|
7438
|
+
}
|
|
7417
7439
|
}
|
|
7418
7440
|
if (opts.dryRun) {
|
|
7419
7441
|
outcomes.push({ role, action: "updated", agentId: row.id });
|
|
@@ -7435,7 +7457,7 @@ async function syncPersonas(route, opts) {
|
|
|
7435
7457
|
continue;
|
|
7436
7458
|
}
|
|
7437
7459
|
if (isPromptGateRejection(e)) {
|
|
7438
|
-
agentPersonas[role] = { agentId: row.id, lastSyncedUpdatedAt: row.updated_at, historyId: cached.historyId };
|
|
7460
|
+
agentPersonas[role] = { agentId: row.id, lastSyncedUpdatedAt: row.updated_at, ...cached?.historyId ? { historyId: cached.historyId } : {} };
|
|
7439
7461
|
outcomes.push({ role, action: "overridden", agentId: row.id });
|
|
7440
7462
|
continue;
|
|
7441
7463
|
}
|
|
@@ -7604,7 +7626,20 @@ async function syncSkills(route, opts) {
|
|
|
7604
7626
|
continue;
|
|
7605
7627
|
}
|
|
7606
7628
|
if (row.description === skill.description && row.prompt === skill.prompt) {
|
|
7607
|
-
|
|
7629
|
+
let anchoredAt = row.updated_at;
|
|
7630
|
+
if (!opts.dryRun && needsBaselineBackfill(skillsModel, row)) {
|
|
7631
|
+
try {
|
|
7632
|
+
anchoredAt = (await client2.records.update(
|
|
7633
|
+
skillsModel.id,
|
|
7634
|
+
row.id,
|
|
7635
|
+
promptSourceFields(skillsModel, skill.prompt),
|
|
7636
|
+
row.updated_at
|
|
7637
|
+
)).updated_at;
|
|
7638
|
+
} catch (e) {
|
|
7639
|
+
if (!(e instanceof StaleWriteError7) && !isPromptGateRejection(e)) throw e;
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
agentSkills[skill.name] = { skillId: row.id, lastSyncedUpdatedAt: anchoredAt };
|
|
7608
7643
|
outcomes.push({ name: skill.name, action: "unchanged", skillId: row.id });
|
|
7609
7644
|
continue;
|
|
7610
7645
|
}
|
|
@@ -7613,7 +7648,32 @@ async function syncSkills(route, opts) {
|
|
|
7613
7648
|
outcomes.push({ name: skill.name, action: "overridden", skillId: row.id });
|
|
7614
7649
|
continue;
|
|
7615
7650
|
}
|
|
7616
|
-
const
|
|
7651
|
+
const body = { description: skill.description, prompt: skill.prompt, ...promptSourceFields(skillsModel, skill.prompt) };
|
|
7652
|
+
if (opts.force) {
|
|
7653
|
+
if (opts.dryRun) {
|
|
7654
|
+
outcomes.push({ name: skill.name, action: "forced", skillId: row.id });
|
|
7655
|
+
continue;
|
|
7656
|
+
}
|
|
7657
|
+
try {
|
|
7658
|
+
const updated = await client2.records.update(skillsModel.id, row.id, body);
|
|
7659
|
+
agentSkills[skill.name] = { skillId: row.id, lastSyncedUpdatedAt: updated.updated_at };
|
|
7660
|
+
outcomes.push({ name: skill.name, action: "forced", skillId: row.id });
|
|
7661
|
+
} catch (e) {
|
|
7662
|
+
if (!isPromptGateRejection(e)) throw e;
|
|
7663
|
+
outcomes.push({ name: skill.name, action: "overridden", skillId: row.id });
|
|
7664
|
+
}
|
|
7665
|
+
continue;
|
|
7666
|
+
}
|
|
7667
|
+
let knownBaseline;
|
|
7668
|
+
if (hasPromptBaselineColumn(skillsModel) && typeof row.prompt_baseline === "string") {
|
|
7669
|
+
if (row.prompt !== row.prompt_baseline) {
|
|
7670
|
+
outcomes.push({ name: skill.name, action: "diverged", skillId: row.id });
|
|
7671
|
+
continue;
|
|
7672
|
+
}
|
|
7673
|
+
knownBaseline = row.updated_at;
|
|
7674
|
+
} else {
|
|
7675
|
+
knownBaseline = cache[skill.name]?.skillId === row.id ? cache[skill.name]?.lastSyncedUpdatedAt : void 0;
|
|
7676
|
+
}
|
|
7617
7677
|
if (!knownBaseline) {
|
|
7618
7678
|
outcomes.push({ name: skill.name, action: "diverged", skillId: row.id });
|
|
7619
7679
|
continue;
|
|
@@ -7626,7 +7686,7 @@ async function syncSkills(route, opts) {
|
|
|
7626
7686
|
const updated = await client2.records.update(
|
|
7627
7687
|
skillsModel.id,
|
|
7628
7688
|
row.id,
|
|
7629
|
-
|
|
7689
|
+
body,
|
|
7630
7690
|
knownBaseline
|
|
7631
7691
|
);
|
|
7632
7692
|
agentSkills[skill.name] = { skillId: row.id, lastSyncedUpdatedAt: updated.updated_at };
|
|
@@ -7655,6 +7715,8 @@ function describeSkillSyncOutcome(o) {
|
|
|
7655
7715
|
return `${o.name}: already in sync`;
|
|
7656
7716
|
case "overridden":
|
|
7657
7717
|
return `${o.name}: override in place \u2014 prompt not synced (clear "Customize prompt" on the Agent Skills row to resume)`;
|
|
7718
|
+
case "forced":
|
|
7719
|
+
return `${o.name}: overwritten from crew's local file (--force)`;
|
|
7658
7720
|
case "diverged":
|
|
7659
7721
|
return `${o.name}: HAS LOCAL EDITS \u2014 crew's default is newer but was NOT applied; review ${o.skillId} in the app before syncing again`;
|
|
7660
7722
|
}
|
|
@@ -7679,6 +7741,7 @@ async function fetchSkillOverrides(route, opts) {
|
|
|
7679
7741
|
for (const row of rows) {
|
|
7680
7742
|
const name = row.name;
|
|
7681
7743
|
if (row.prompt === local.get(name)?.prompt) continue;
|
|
7744
|
+
if (row.prompt_customized !== true && row.prompt === row.prompt_baseline) continue;
|
|
7682
7745
|
const cached = cache[name];
|
|
7683
7746
|
if (cached?.skillId === row.id && cached.lastSyncedUpdatedAt === row.updated_at) continue;
|
|
7684
7747
|
out[name] = row.prompt;
|
|
@@ -12178,7 +12241,7 @@ function usage() {
|
|
|
12178
12241
|
crew inbox [--member NAME] your tickets across every workspace (or a colleague's)
|
|
12179
12242
|
crew connect resolve a workspace's ids into a crew.yaml block (--no-mcp skips registering the Tablation MCP server with Claude Code; --mcp replace overwrites a different one)
|
|
12180
12243
|
crew disconnect remove what connect installed for Pair (Claude MCP; Codex/Gemini instructions block and MCP entry per ship.pair)
|
|
12181
|
-
crew agents sync [route] [--force] push crew's personas AND skill files into the workspace Agents/Agent Skills tables (--force overwrites even a diverged persona)
|
|
12244
|
+
crew agents sync [route] [--force] push crew's personas AND skill files into the workspace Agents/Agent Skills tables (--force overwrites even a diverged persona or skill; never one marked Customize prompt)
|
|
12182
12245
|
crew agents prompt R [route] print one persona's current prompt (e.g. R=pair, for a SessionStart hook; --harness H adds which CLI it serves)
|
|
12183
12246
|
crew skills sync [route] push only crew's skill files (e.g. grill-me) into the workspace Agent Skills table
|
|
12184
12247
|
crew repos add [ROUTE] [NAME] [PATH] attach a local checkout to a route in crew.yaml (--dry-run previews)
|
|
@@ -13619,7 +13682,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
13619
13682
|
break;
|
|
13620
13683
|
}
|
|
13621
13684
|
if (sub !== "sync") {
|
|
13622
|
-
process.stderr.write("crew agents sync [route] [--force] push crew's personas (Developer/Design/QA/Triage/Pair) AND skill files (e.g. grill-me) into the workspace Agents/Agent Skills tables (--force overwrites even a diverged persona)\n");
|
|
13685
|
+
process.stderr.write("crew agents sync [route] [--force] push crew's personas (Developer/Design/QA/Triage/Pair) AND skill files (e.g. grill-me) into the workspace Agents/Agent Skills tables (--force overwrites even a diverged persona or skill; never one marked Customize prompt)\n");
|
|
13623
13686
|
process.stderr.write(`crew agents prompt <role> [route] print a persona's current prompt (roles: ${ROLE_NAMES.join(", ")})
|
|
13624
13687
|
`);
|
|
13625
13688
|
process.exit(2);
|
|
@@ -13662,7 +13725,7 @@ ${changed2.map((c) => ` - ${c}
|
|
|
13662
13725
|
`);
|
|
13663
13726
|
let skillResult;
|
|
13664
13727
|
try {
|
|
13665
|
-
skillResult = await syncSkills(target, { userAgent: cfg.ship.userAgent, dryRun });
|
|
13728
|
+
skillResult = await syncSkills(target, { userAgent: cfg.ship.userAgent, dryRun, force });
|
|
13666
13729
|
} catch (e) {
|
|
13667
13730
|
if (e instanceof SkillSyncError) {
|
|
13668
13731
|
process.stderr.write(`crew agents sync: ${e.message}
|
package/package.json
CHANGED