runwork 0.16.1 → 0.17.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.
- package/dist/index.js +308 -90
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7381,7 +7381,7 @@ function createKeyboardListener() {
|
|
|
7381
7381
|
}
|
|
7382
7382
|
|
|
7383
7383
|
// src/generated/version.ts
|
|
7384
|
-
var VERSION = "0.
|
|
7384
|
+
var VERSION = "0.17.0";
|
|
7385
7385
|
|
|
7386
7386
|
// src/commands/dev.ts
|
|
7387
7387
|
var exports_dev = {};
|
|
@@ -11118,6 +11118,33 @@ function formatCombinedDigest(sessions, opts = { days: 7 }) {
|
|
|
11118
11118
|
// src/agents/utils/json-config.ts
|
|
11119
11119
|
import { readFileSync as readFileSync22, writeFileSync as writeFileSync14, mkdirSync as mkdirSync13, existsSync as existsSync25 } from "fs";
|
|
11120
11120
|
import { dirname as dirname5 } from "path";
|
|
11121
|
+
|
|
11122
|
+
// src/sync/hash.ts
|
|
11123
|
+
import { createHash as createHash2 } from "crypto";
|
|
11124
|
+
function contentHash(content) {
|
|
11125
|
+
return "sha256:" + createHash2("sha256").update(content).digest("hex");
|
|
11126
|
+
}
|
|
11127
|
+
function stableStringify(value) {
|
|
11128
|
+
return JSON.stringify(sortValue(value));
|
|
11129
|
+
}
|
|
11130
|
+
function sortValue(value) {
|
|
11131
|
+
if (Array.isArray(value))
|
|
11132
|
+
return value.map(sortValue);
|
|
11133
|
+
if (value !== null && typeof value === "object") {
|
|
11134
|
+
const obj = value;
|
|
11135
|
+
const sorted = {};
|
|
11136
|
+
for (const key of Object.keys(obj).sort()) {
|
|
11137
|
+
sorted[key] = sortValue(obj[key]);
|
|
11138
|
+
}
|
|
11139
|
+
return sorted;
|
|
11140
|
+
}
|
|
11141
|
+
return value;
|
|
11142
|
+
}
|
|
11143
|
+
function configHash(value) {
|
|
11144
|
+
return contentHash(stableStringify(value));
|
|
11145
|
+
}
|
|
11146
|
+
|
|
11147
|
+
// src/agents/utils/json-config.ts
|
|
11121
11148
|
function isRunworkManagedKey(key) {
|
|
11122
11149
|
return key === RUNWORK_WORKSPACE_MCP_NAME || key.startsWith(RUNWORK_MCP_PREFIX) || key.startsWith(RUNWORK_MCP_PREFIX_LEGACY);
|
|
11123
11150
|
}
|
|
@@ -11156,6 +11183,14 @@ function removeRunworkMcpServers(filePath, topKey) {
|
|
|
11156
11183
|
function mergeJsonMcpServers(filePath, servers, topKey) {
|
|
11157
11184
|
const config = readJsonConfig(filePath);
|
|
11158
11185
|
const existing = config[topKey] || {};
|
|
11186
|
+
const managedBefore = {};
|
|
11187
|
+
for (const key of Object.keys(existing)) {
|
|
11188
|
+
if (isRunworkManagedKey(key))
|
|
11189
|
+
managedBefore[key] = existing[key];
|
|
11190
|
+
}
|
|
11191
|
+
const changed = configHash(managedBefore) !== configHash(servers);
|
|
11192
|
+
if (!changed)
|
|
11193
|
+
return false;
|
|
11159
11194
|
for (const key of Object.keys(existing)) {
|
|
11160
11195
|
if (isRunworkManagedKey(key)) {
|
|
11161
11196
|
delete existing[key];
|
|
@@ -11164,6 +11199,7 @@ function mergeJsonMcpServers(filePath, servers, topKey) {
|
|
|
11164
11199
|
Object.assign(existing, servers);
|
|
11165
11200
|
config[topKey] = existing;
|
|
11166
11201
|
writeJsonConfig(filePath, config);
|
|
11202
|
+
return true;
|
|
11167
11203
|
}
|
|
11168
11204
|
|
|
11169
11205
|
// src/agents/utils/instruction-hint.ts
|
|
@@ -11487,6 +11523,19 @@ function resolveAgentDefaults(input) {
|
|
|
11487
11523
|
};
|
|
11488
11524
|
}
|
|
11489
11525
|
|
|
11526
|
+
// src/ui/verbosity.ts
|
|
11527
|
+
var verbose = false;
|
|
11528
|
+
function setVerbose(value) {
|
|
11529
|
+
verbose = value;
|
|
11530
|
+
}
|
|
11531
|
+
function isVerbose() {
|
|
11532
|
+
return verbose;
|
|
11533
|
+
}
|
|
11534
|
+
function vlog(...args) {
|
|
11535
|
+
if (verbose)
|
|
11536
|
+
console.log(...args);
|
|
11537
|
+
}
|
|
11538
|
+
|
|
11490
11539
|
// src/agents/claude-code.ts
|
|
11491
11540
|
var PLUGIN_NAME = "runwork";
|
|
11492
11541
|
var PLUGIN_VERSION = "1.0.0";
|
|
@@ -11589,7 +11638,7 @@ class ClaudeCodeAdapter {
|
|
|
11589
11638
|
]
|
|
11590
11639
|
};
|
|
11591
11640
|
writeFileSync16(join21(hooksDir, "hooks.json"), JSON.stringify(hooksManifest, null, 2));
|
|
11592
|
-
|
|
11641
|
+
vlog(` [Claude Code] Installed SessionStart hook (${label}) -> ${scriptPath}`);
|
|
11593
11642
|
}
|
|
11594
11643
|
async writeSkills(skills, scope) {
|
|
11595
11644
|
const baseDir = scope === "project" ? join21(process.cwd(), ".claude", "skills") : join21(homedir5(), ".claude", "skills");
|
|
@@ -11622,6 +11671,7 @@ class ClaudeCodeAdapter {
|
|
|
11622
11671
|
}
|
|
11623
11672
|
this.registerPlugin(pluginDir);
|
|
11624
11673
|
}
|
|
11674
|
+
return skills.length;
|
|
11625
11675
|
}
|
|
11626
11676
|
async writeBuiltInHooks(scope) {
|
|
11627
11677
|
if (scope !== "user")
|
|
@@ -12116,7 +12166,7 @@ ${instructions}`;
|
|
|
12116
12166
|
lastUpdated: new Date().toISOString()
|
|
12117
12167
|
};
|
|
12118
12168
|
writeJsonConfig(marketplacesPath, marketplaces);
|
|
12119
|
-
|
|
12169
|
+
vlog(` [Claude Code] ${wasRegistered ? "Refreshed" : "Registered"} plugin ` + `${pluginKey} v${PLUGIN_VERSION} -> ${installedPath}`);
|
|
12120
12170
|
const settingsPath = join21(homedir5(), ".claude", "settings.json");
|
|
12121
12171
|
const settings = readJsonConfig(settingsPath);
|
|
12122
12172
|
if (!settings["enabledPlugins"]) {
|
|
@@ -12416,12 +12466,12 @@ class ClaudeDesktopAdapter {
|
|
|
12416
12466
|
if (rpm) {
|
|
12417
12467
|
writePluginMetadata(rpm.pluginPath, getPluginMetadata());
|
|
12418
12468
|
writePluginSkills(rpm.pluginPath, skills);
|
|
12419
|
-
return;
|
|
12469
|
+
return skills.length;
|
|
12420
12470
|
}
|
|
12421
12471
|
const pluginsDir = findCoworkPluginsDir();
|
|
12422
12472
|
if (!pluginsDir) {
|
|
12423
12473
|
console.warn(" [Claude Desktop] Cowork plugins directory not found. Open Claude Desktop at least once first.");
|
|
12424
|
-
return;
|
|
12474
|
+
return 0;
|
|
12425
12475
|
}
|
|
12426
12476
|
const cacheDir = join23(pluginsDir, "cache", "runwork", PLUGIN_NAME2, PLUGIN_VERSION2);
|
|
12427
12477
|
const marketRoot = join23(pluginsDir, "marketplaces", "runwork");
|
|
@@ -12456,6 +12506,7 @@ class ClaudeDesktopAdapter {
|
|
|
12456
12506
|
};
|
|
12457
12507
|
writeJsonConfig(marketplacesPath, marketplaces);
|
|
12458
12508
|
setCoworkPluginEnabled(pluginsDir, true);
|
|
12509
|
+
return skills.length;
|
|
12459
12510
|
}
|
|
12460
12511
|
async writeInstructionHint(hint, _scope) {
|
|
12461
12512
|
for (const path2 of getCoworkMemoryClaudeMdPaths()) {
|
|
@@ -12946,7 +12997,7 @@ class CursorAdapter {
|
|
|
12946
12997
|
}
|
|
12947
12998
|
async writeSkills(skills, scope) {
|
|
12948
12999
|
if (scope === "user")
|
|
12949
|
-
return;
|
|
13000
|
+
return 0;
|
|
12950
13001
|
const rulesDir = join24(process.cwd(), ".cursor", "rules");
|
|
12951
13002
|
mkdirSync18(rulesDir, { recursive: true });
|
|
12952
13003
|
for (const skill of skills) {
|
|
@@ -12958,6 +13009,7 @@ alwaysApply: false
|
|
|
12958
13009
|
${skill.content}`;
|
|
12959
13010
|
writeFileSync19(join24(rulesDir, `${skill.filename}.mdc`), mdcContent);
|
|
12960
13011
|
}
|
|
13012
|
+
return skills.length;
|
|
12961
13013
|
}
|
|
12962
13014
|
async writeInstructionHint(hint, scope) {
|
|
12963
13015
|
const filePath = scope === "project" ? join24(process.cwd(), ".cursor", "rules", "runwork.mdc") : join24(homedir7(), ".cursor", "rules", "runwork.mdc");
|
|
@@ -13210,7 +13262,7 @@ class WindsurfAdapter {
|
|
|
13210
13262
|
}
|
|
13211
13263
|
async writeSkills(skills, scope) {
|
|
13212
13264
|
if (scope === "user")
|
|
13213
|
-
return;
|
|
13265
|
+
return 0;
|
|
13214
13266
|
const rulesDir = join25(process.cwd(), ".windsurf", "rules");
|
|
13215
13267
|
mkdirSync19(rulesDir, { recursive: true });
|
|
13216
13268
|
for (const skill of skills) {
|
|
@@ -13221,6 +13273,7 @@ trigger: manual
|
|
|
13221
13273
|
${skill.content}`;
|
|
13222
13274
|
writeFileSync20(join25(rulesDir, `${skill.filename}.md`), content);
|
|
13223
13275
|
}
|
|
13276
|
+
return skills.length;
|
|
13224
13277
|
}
|
|
13225
13278
|
async writeTeamInstructions(instructions, scope) {
|
|
13226
13279
|
const filePath = scope === "project" ? join25(process.cwd(), ".windsurf", "rules", "runwork-team.md") : join25(getWindsurfDataDir(), "rules", "runwork-team.md");
|
|
@@ -13468,7 +13521,7 @@ var AGENT_REGISTRY = [
|
|
|
13468
13521
|
]
|
|
13469
13522
|
},
|
|
13470
13523
|
launch: { app: { macos: "Codex", windows: "Codex" } },
|
|
13471
|
-
logo: "
|
|
13524
|
+
logo: "codex",
|
|
13472
13525
|
downloadUrl: "https://openai.com/codex/",
|
|
13473
13526
|
skillsPaths: { global: ".codex/skills", project: ".agents/skills" },
|
|
13474
13527
|
instructionFile: { global: ".codex/instructions.md", project: "AGENTS.md" },
|
|
@@ -13493,7 +13546,7 @@ var AGENT_REGISTRY = [
|
|
|
13493
13546
|
category: "cli",
|
|
13494
13547
|
detection: { method: "binary", target: "codex" },
|
|
13495
13548
|
launch: { cli: "codex", cliAcceptsPrompt: true },
|
|
13496
|
-
logo: "
|
|
13549
|
+
logo: "codex",
|
|
13497
13550
|
downloadUrl: "https://github.com/openai/codex",
|
|
13498
13551
|
skillsPaths: { global: ".codex/skills", project: ".agents/skills" },
|
|
13499
13552
|
instructionFile: { global: ".codex/instructions.md", project: "AGENTS.md" },
|
|
@@ -14016,6 +14069,7 @@ class CodexAdapter {
|
|
|
14016
14069
|
mkdirSync20(skillDir, { recursive: true });
|
|
14017
14070
|
writeFileSync21(join28(skillDir, "SKILL.md"), buildSkillMd2(skill));
|
|
14018
14071
|
}
|
|
14072
|
+
return skills.length;
|
|
14019
14073
|
}
|
|
14020
14074
|
async writeInstructionHint(hint, scope) {
|
|
14021
14075
|
const filePath = scope === "project" ? join28(process.cwd(), "AGENTS.md") : join28(homedir11(), ".codex", "AGENTS.md");
|
|
@@ -14377,12 +14431,13 @@ class ClineAdapter {
|
|
|
14377
14431
|
}
|
|
14378
14432
|
async writeSkills(skills, scope) {
|
|
14379
14433
|
if (scope === "user")
|
|
14380
|
-
return;
|
|
14434
|
+
return 0;
|
|
14381
14435
|
const rulesDir = join29(process.cwd(), ".clinerules");
|
|
14382
14436
|
mkdirSync21(rulesDir, { recursive: true });
|
|
14383
14437
|
for (const skill of skills) {
|
|
14384
14438
|
writeFileSync22(join29(rulesDir, `${skill.filename}.md`), buildSkillMd2(skill));
|
|
14385
14439
|
}
|
|
14440
|
+
return skills.length;
|
|
14386
14441
|
}
|
|
14387
14442
|
async writeInstructionHint(hint, scope) {
|
|
14388
14443
|
if (scope === "user")
|
|
@@ -14507,6 +14562,7 @@ class GeminiAdapter {
|
|
|
14507
14562
|
mkdirSync22(skillDir, { recursive: true });
|
|
14508
14563
|
writeFileSync23(join30(skillDir, "SKILL.md"), buildSkillMd2(skill));
|
|
14509
14564
|
}
|
|
14565
|
+
return skills.length;
|
|
14510
14566
|
}
|
|
14511
14567
|
async writeInstructionHint(hint, scope) {
|
|
14512
14568
|
const filePath = scope === "project" ? join30(process.cwd(), "GEMINI.md") : join30(homedir13(), ".gemini", "GEMINI.md");
|
|
@@ -14606,13 +14662,13 @@ class GenericAgentAdapter {
|
|
|
14606
14662
|
}
|
|
14607
14663
|
async writeSkills(skills, scope) {
|
|
14608
14664
|
if (!this.def.skillsPaths)
|
|
14609
|
-
return;
|
|
14665
|
+
return 0;
|
|
14610
14666
|
const pathTemplate = scope === "project" ? this.def.skillsPaths.project : this.def.skillsPaths.global;
|
|
14611
14667
|
if (!pathTemplate)
|
|
14612
|
-
return;
|
|
14668
|
+
return 0;
|
|
14613
14669
|
const baseDir = resolveToAbsolute(pathTemplate, scope === "project" ? "project" : "global");
|
|
14614
14670
|
if (!baseDir)
|
|
14615
|
-
return;
|
|
14671
|
+
return 0;
|
|
14616
14672
|
for (const skill of skills) {
|
|
14617
14673
|
if (skill.name !== skill.filename) {
|
|
14618
14674
|
const oldDir = join31(baseDir, skill.name);
|
|
@@ -14626,6 +14682,7 @@ class GenericAgentAdapter {
|
|
|
14626
14682
|
mkdirSync23(skillDir, { recursive: true });
|
|
14627
14683
|
writeFileSync24(join31(skillDir, "SKILL.md"), buildSkillMd2(skill));
|
|
14628
14684
|
}
|
|
14685
|
+
return skills.length;
|
|
14629
14686
|
}
|
|
14630
14687
|
async writeInstructionHint(hint, scope) {
|
|
14631
14688
|
if (!this.def.instructionFile)
|
|
@@ -14740,9 +14797,9 @@ function printNoAgentsMessage() {
|
|
|
14740
14797
|
}
|
|
14741
14798
|
|
|
14742
14799
|
// src/utils/insight-id.ts
|
|
14743
|
-
import { createHash as
|
|
14800
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
14744
14801
|
function computeInsightId(userSeed, localKey) {
|
|
14745
|
-
return
|
|
14802
|
+
return createHash3("sha256").update(`${userSeed}:${localKey}`).digest("hex").slice(0, 22);
|
|
14746
14803
|
}
|
|
14747
14804
|
function insightLocalKey(teaches, slug) {
|
|
14748
14805
|
return `${teaches}:${slug}`.toLowerCase().replace(/[^a-z0-9:_-]+/g, "-").replace(/-+/g, "-");
|
|
@@ -16664,19 +16721,6 @@ async function collectTelemetryEvents(params) {
|
|
|
16664
16721
|
const now = params.now ?? new Date().toISOString();
|
|
16665
16722
|
const events = [];
|
|
16666
16723
|
const adapterResults = [];
|
|
16667
|
-
const previouslyReported = new Set(params.state.reportedAgentSlugs ?? []);
|
|
16668
|
-
const newlyReportedAgents = [];
|
|
16669
|
-
for (const slug of params.state.configuredAgents) {
|
|
16670
|
-
if (!previouslyReported.has(slug)) {
|
|
16671
|
-
events.push({
|
|
16672
|
-
eventType: "local_agent.detected",
|
|
16673
|
-
agentSlug: slug,
|
|
16674
|
-
metadata: { installed: true },
|
|
16675
|
-
timestamp: now
|
|
16676
|
-
});
|
|
16677
|
-
newlyReportedAgents.push(slug);
|
|
16678
|
-
}
|
|
16679
|
-
}
|
|
16680
16724
|
for (const adapter2 of params.adapters) {
|
|
16681
16725
|
let stats = "unsupported";
|
|
16682
16726
|
let skills = "unsupported";
|
|
@@ -16768,11 +16812,12 @@ async function collectTelemetryEvents(params) {
|
|
|
16768
16812
|
syncedMcpServers: params.syncedMcpServersCount,
|
|
16769
16813
|
teamInstructionsApplied: params.teamInstructionsApplied,
|
|
16770
16814
|
agentConfigsApplied: params.agentConfigsApplied,
|
|
16815
|
+
agents: [...params.state.configuredAgents],
|
|
16771
16816
|
...params.state.persona?.label ? { persona: params.state.persona.label } : {}
|
|
16772
16817
|
},
|
|
16773
16818
|
timestamp: now
|
|
16774
16819
|
});
|
|
16775
|
-
return { events, adapterResults,
|
|
16820
|
+
return { events, adapterResults, healthReported };
|
|
16776
16821
|
}
|
|
16777
16822
|
function formatStatsLine(stats) {
|
|
16778
16823
|
const parts = [];
|
|
@@ -16818,10 +16863,6 @@ function printTelemetryVerbose(result) {
|
|
|
16818
16863
|
const errSuffix = r.error ? ` (error: ${r.error})` : "";
|
|
16819
16864
|
console.log(` [${r.name}] stats: ${statsLabel}; skills: ${skillsLabel}${errSuffix}`);
|
|
16820
16865
|
}
|
|
16821
|
-
if (result.newlyReportedAgents.length > 0) {
|
|
16822
|
-
console.log(`
|
|
16823
|
-
First-time detections: ${result.newlyReportedAgents.join(", ")}`);
|
|
16824
|
-
}
|
|
16825
16866
|
if (result.healthReported) {
|
|
16826
16867
|
console.log(" Health report: due (daily)");
|
|
16827
16868
|
}
|
|
@@ -17451,12 +17492,6 @@ function buildSaveConversationSkill() {
|
|
|
17451
17492
|
};
|
|
17452
17493
|
}
|
|
17453
17494
|
|
|
17454
|
-
// src/sync/hash.ts
|
|
17455
|
-
import { createHash as createHash3 } from "crypto";
|
|
17456
|
-
function contentHash(content) {
|
|
17457
|
-
return "sha256:" + createHash3("sha256").update(content).digest("hex");
|
|
17458
|
-
}
|
|
17459
|
-
|
|
17460
17495
|
// src/sync/change-detect.ts
|
|
17461
17496
|
function computeSyncPlan(input) {
|
|
17462
17497
|
const { storedHashes, localSkills, remoteSkills } = input;
|
|
@@ -17488,6 +17523,16 @@ function computeSyncPlan(input) {
|
|
|
17488
17523
|
const localChanged = localHash !== null && localHash !== stored.localHash;
|
|
17489
17524
|
const remoteChanged = remoteHash !== stored.remoteHash;
|
|
17490
17525
|
if (!local) {
|
|
17526
|
+
if (remote.source === "app" && !remoteChanged) {
|
|
17527
|
+
plan.skips.push({
|
|
17528
|
+
name: remote.name,
|
|
17529
|
+
action: "skip",
|
|
17530
|
+
source: remote.source,
|
|
17531
|
+
remoteId: remote.remoteId,
|
|
17532
|
+
appId: remote.appId
|
|
17533
|
+
});
|
|
17534
|
+
continue;
|
|
17535
|
+
}
|
|
17491
17536
|
plan.pulls.push({
|
|
17492
17537
|
name: remote.name,
|
|
17493
17538
|
action: "pull",
|
|
@@ -17667,6 +17712,47 @@ function resolveConflictNonInteractive(prefer) {
|
|
|
17667
17712
|
return prefer;
|
|
17668
17713
|
}
|
|
17669
17714
|
|
|
17715
|
+
// src/sync/summary-format.ts
|
|
17716
|
+
function summarizeSkillPlan(plan) {
|
|
17717
|
+
return {
|
|
17718
|
+
added: plan.pulls.filter((p) => p.action === "new-remote").map((p) => p.name),
|
|
17719
|
+
updated: plan.pulls.filter((p) => p.action === "pull").map((p) => p.name),
|
|
17720
|
+
removed: plan.deletions.map((p) => p.name),
|
|
17721
|
+
pushed: plan.pushes.map((p) => p.name),
|
|
17722
|
+
unchanged: plan.skips.length,
|
|
17723
|
+
conflicts: plan.conflicts.length
|
|
17724
|
+
};
|
|
17725
|
+
}
|
|
17726
|
+
function formatNameList(names, cap2 = 6) {
|
|
17727
|
+
if (names.length <= cap2)
|
|
17728
|
+
return names.join(", ");
|
|
17729
|
+
return `${names.slice(0, cap2).join(", ")}, +${names.length - cap2} more`;
|
|
17730
|
+
}
|
|
17731
|
+
function formatSkillSummaryLine(c) {
|
|
17732
|
+
const parts = [];
|
|
17733
|
+
if (c.added.length)
|
|
17734
|
+
parts.push(`${c.added.length} added (${formatNameList(c.added)})`);
|
|
17735
|
+
if (c.updated.length)
|
|
17736
|
+
parts.push(`${c.updated.length} updated (${formatNameList(c.updated)})`);
|
|
17737
|
+
if (c.removed.length)
|
|
17738
|
+
parts.push(`${c.removed.length} removed (${formatNameList(c.removed)})`);
|
|
17739
|
+
if (c.pushed.length)
|
|
17740
|
+
parts.push(`${c.pushed.length} pushed (${formatNameList(c.pushed)})`);
|
|
17741
|
+
if (c.conflicts)
|
|
17742
|
+
parts.push(`${c.conflicts} conflict${c.conflicts === 1 ? "" : "s"}`);
|
|
17743
|
+
parts.push(`${c.unchanged} up to date`);
|
|
17744
|
+
return parts.join(", ");
|
|
17745
|
+
}
|
|
17746
|
+
var REASON_LABEL = {
|
|
17747
|
+
mcp: "MCP",
|
|
17748
|
+
settings: "settings"
|
|
17749
|
+
};
|
|
17750
|
+
function formatRestartChanges(changes) {
|
|
17751
|
+
if (changes.length === 0)
|
|
17752
|
+
return "none";
|
|
17753
|
+
return changes.map((c) => `${c.name} (${c.reasons.map((r) => REASON_LABEL[r]).join(", ")})`).join("; ");
|
|
17754
|
+
}
|
|
17755
|
+
|
|
17670
17756
|
// src/sync/executor.ts
|
|
17671
17757
|
async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
17672
17758
|
const newHashes = {};
|
|
@@ -17682,7 +17768,7 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
17682
17768
|
remoteId: action.remoteId,
|
|
17683
17769
|
appId: action.appId
|
|
17684
17770
|
};
|
|
17685
|
-
|
|
17771
|
+
vlog(` Pulled: ${action.name}`);
|
|
17686
17772
|
}
|
|
17687
17773
|
for (const action of plan.pushes) {
|
|
17688
17774
|
if (!action.localContent || !action.remoteId)
|
|
@@ -17699,7 +17785,7 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
17699
17785
|
source: "external",
|
|
17700
17786
|
remoteId: action.remoteId
|
|
17701
17787
|
};
|
|
17702
|
-
|
|
17788
|
+
vlog(` Pushed: ${action.name}`);
|
|
17703
17789
|
}
|
|
17704
17790
|
for (const action of plan.conflicts) {
|
|
17705
17791
|
const resolution = resolvedConflicts.get(action.name);
|
|
@@ -17713,7 +17799,7 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
17713
17799
|
});
|
|
17714
17800
|
const hash = contentHash(action.localContent);
|
|
17715
17801
|
newHashes[action.name] = { localHash: hash, remoteHash: hash, source: "external", remoteId: action.remoteId };
|
|
17716
|
-
|
|
17802
|
+
vlog(` Pushed (conflict resolved): ${action.name}`);
|
|
17717
17803
|
} else if (resolution === "remote" && action.remoteContent) {
|
|
17718
17804
|
const skillFile = makeSkillFile(action.name, action.remoteContent);
|
|
17719
17805
|
await writeSkillToAgents(skillFile, action.source, ctx);
|
|
@@ -17723,12 +17809,12 @@ async function executeSyncPlan(plan, resolvedConflicts, ctx) {
|
|
|
17723
17809
|
source: "external",
|
|
17724
17810
|
remoteId: action.remoteId
|
|
17725
17811
|
};
|
|
17726
|
-
|
|
17812
|
+
vlog(` Pulled (conflict resolved): ${action.name}`);
|
|
17727
17813
|
}
|
|
17728
17814
|
}
|
|
17729
17815
|
for (const _action of plan.skips) {}
|
|
17730
17816
|
for (const action of plan.deletions) {
|
|
17731
|
-
|
|
17817
|
+
vlog(` Deleted locally: ${action.name}`);
|
|
17732
17818
|
}
|
|
17733
17819
|
return newHashes;
|
|
17734
17820
|
}
|
|
@@ -17758,6 +17844,53 @@ function extractDescription(content) {
|
|
|
17758
17844
|
return match ? match[1].trim() : "";
|
|
17759
17845
|
}
|
|
17760
17846
|
|
|
17847
|
+
// src/sync/restart-stamp.ts
|
|
17848
|
+
function computeRestartReasons(input) {
|
|
17849
|
+
const settingsSet = new Set(input.settingsChangedSlugs);
|
|
17850
|
+
const out = {};
|
|
17851
|
+
for (const agent of input.agents) {
|
|
17852
|
+
if (agent.connectOnly)
|
|
17853
|
+
continue;
|
|
17854
|
+
const reasons = [];
|
|
17855
|
+
if ((input.mcpChanged || agent.isNew) && agent.receivesMcp)
|
|
17856
|
+
reasons.push("mcp");
|
|
17857
|
+
if (settingsSet.has(agent.slug))
|
|
17858
|
+
reasons.push("settings");
|
|
17859
|
+
if (reasons.length > 0)
|
|
17860
|
+
out[agent.slug] = reasons;
|
|
17861
|
+
}
|
|
17862
|
+
return out;
|
|
17863
|
+
}
|
|
17864
|
+
function summarizeRealSkillChanges(newLocalHashes, priorLocalHashes, materializedDeletions) {
|
|
17865
|
+
const added = [];
|
|
17866
|
+
const updated = [];
|
|
17867
|
+
for (const [name, hash] of Object.entries(newLocalHashes)) {
|
|
17868
|
+
if (!(name in priorLocalHashes))
|
|
17869
|
+
added.push(name);
|
|
17870
|
+
else if (priorLocalHashes[name] !== hash)
|
|
17871
|
+
updated.push(name);
|
|
17872
|
+
}
|
|
17873
|
+
return {
|
|
17874
|
+
added: added.sort(),
|
|
17875
|
+
updated: updated.sort(),
|
|
17876
|
+
removed: [...materializedDeletions].sort()
|
|
17877
|
+
};
|
|
17878
|
+
}
|
|
17879
|
+
function hasRealSkillChange(c) {
|
|
17880
|
+
return c.added.length > 0 || c.updated.length > 0 || c.removed.length > 0;
|
|
17881
|
+
}
|
|
17882
|
+
function sameStringSet(a, b) {
|
|
17883
|
+
const setA = new Set(a ?? []);
|
|
17884
|
+
const setB = new Set(b ?? []);
|
|
17885
|
+
if (setA.size !== setB.size)
|
|
17886
|
+
return false;
|
|
17887
|
+
for (const item of setA) {
|
|
17888
|
+
if (!setB.has(item))
|
|
17889
|
+
return false;
|
|
17890
|
+
}
|
|
17891
|
+
return true;
|
|
17892
|
+
}
|
|
17893
|
+
|
|
17761
17894
|
// src/commands/sync.ts
|
|
17762
17895
|
async function printAdoptionHint(credentials, workspaceId) {
|
|
17763
17896
|
if (!workspaceId)
|
|
@@ -17842,6 +17975,7 @@ async function refreshConfiguredAgents(state) {
|
|
|
17842
17975
|
}
|
|
17843
17976
|
async function syncFromState(state, statePath2, credentials, opts) {
|
|
17844
17977
|
const client = new ApiClient(credentials);
|
|
17978
|
+
setVerbose(!!opts.verbose);
|
|
17845
17979
|
if (!state.workspaceName || state.workspaceName === state.workspaceId || !state.workspaceSlug) {
|
|
17846
17980
|
try {
|
|
17847
17981
|
const workspaces = await client.listWorkspaces();
|
|
@@ -17853,11 +17987,12 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
17853
17987
|
} catch {}
|
|
17854
17988
|
}
|
|
17855
17989
|
console.log(`Syncing workspace: ${state.workspaceName || state.workspaceId}`);
|
|
17990
|
+
let addedThisSync = [];
|
|
17856
17991
|
if (shouldRedetect(state, opts)) {
|
|
17857
17992
|
console.log(" Detecting installed agents...");
|
|
17858
|
-
|
|
17859
|
-
if (
|
|
17860
|
-
console.log(` Detected new agent${
|
|
17993
|
+
addedThisSync = await refreshConfiguredAgents(state);
|
|
17994
|
+
if (addedThisSync.length > 0) {
|
|
17995
|
+
console.log(` Detected new agent${addedThisSync.length > 1 ? "s" : ""}: ${addedThisSync.join(", ")}`);
|
|
17861
17996
|
}
|
|
17862
17997
|
}
|
|
17863
17998
|
console.log(" Fetching workspace data...");
|
|
@@ -17899,6 +18034,8 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
17899
18034
|
headers: { Authorization: `Bearer ${credentials.apiKey}` },
|
|
17900
18035
|
description: "Runwork workspace tools: query entities, trigger workflows, manage integrations, run agents, and access shared data across your team's apps."
|
|
17901
18036
|
});
|
|
18037
|
+
const mcpEntriesHash = configHash([...mcpEntries].sort((a, b) => a.name.localeCompare(b.name)));
|
|
18038
|
+
const mcpChanged = state.lastMcpEntriesHash !== undefined && state.lastMcpEntriesHash !== mcpEntriesHash;
|
|
17902
18039
|
const remoteSkills = [];
|
|
17903
18040
|
for (const s of externalSkills) {
|
|
17904
18041
|
remoteSkills.push({ name: s.name, content: s.content, source: "external", remoteId: s.id });
|
|
@@ -17928,12 +18065,9 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
17928
18065
|
plan.skips.push(...plan.conflicts.map((c) => ({ ...c, action: "skip" })));
|
|
17929
18066
|
plan.conflicts = [];
|
|
17930
18067
|
}
|
|
17931
|
-
|
|
17932
|
-
if (
|
|
18068
|
+
console.log(` Skills: ${formatSkillSummaryLine(summarizeSkillPlan(plan))}`);
|
|
18069
|
+
if (isVerbose())
|
|
17933
18070
|
printSyncSummary(plan);
|
|
17934
|
-
} else {
|
|
17935
|
-
console.log(" All skills up to date.");
|
|
17936
|
-
}
|
|
17937
18071
|
const adapters = [];
|
|
17938
18072
|
for (const slug of state.configuredAgents) {
|
|
17939
18073
|
const adapter2 = getAdapterBySlug(slug);
|
|
@@ -17973,6 +18107,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
17973
18107
|
}
|
|
17974
18108
|
}
|
|
17975
18109
|
}
|
|
18110
|
+
const settingsChangedSlugs = [];
|
|
17976
18111
|
const scopes = state.scope === "both" ? ["project", "user"] : [state.scope];
|
|
17977
18112
|
if (adapters.length > 0) {
|
|
17978
18113
|
console.log(` Syncing to: ${adapters.map((a) => a.name).join(", ")}`);
|
|
@@ -18021,6 +18156,8 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18021
18156
|
buildSaveConversationSkill()
|
|
18022
18157
|
];
|
|
18023
18158
|
const builtInNames = builtInSkills.map((s) => s.name);
|
|
18159
|
+
const builtInSkillsHash = configHash(builtInSkills.map((s) => s.content));
|
|
18160
|
+
const builtInSkillsChanged = state.builtInSkillsHash !== undefined && state.builtInSkillsHash !== builtInSkillsHash;
|
|
18024
18161
|
const summary = {
|
|
18025
18162
|
adaptersProcessed: 0,
|
|
18026
18163
|
adaptersFailed: 0,
|
|
@@ -18030,16 +18167,18 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18030
18167
|
instructionHintWrites: 0,
|
|
18031
18168
|
hookInstallCalls: 0
|
|
18032
18169
|
};
|
|
18170
|
+
const mcpFailedAdapters = new Set;
|
|
18171
|
+
const skillFailedAdapters = new Set;
|
|
18033
18172
|
for (const adapter2 of adapters) {
|
|
18034
18173
|
if (isConnectOnlyAgent(getRegistryAgent(adapter2.slug))) {
|
|
18035
|
-
|
|
18174
|
+
vlog(` [${adapter2.name}] Connect-only agent: no local files to sync`);
|
|
18036
18175
|
summary.adaptersProcessed++;
|
|
18037
18176
|
continue;
|
|
18038
18177
|
}
|
|
18039
18178
|
let adapterFailedAnyScope = false;
|
|
18040
18179
|
for (const scope of scopes) {
|
|
18041
|
-
|
|
18042
|
-
|
|
18180
|
+
if (adapter2.supportsSkills()) {
|
|
18181
|
+
try {
|
|
18043
18182
|
const skipAppSkills = adapter2.mcpProvidesSkills && mcpEntries.length > 0;
|
|
18044
18183
|
const scopeSkills = remoteSkills.filter((s) => {
|
|
18045
18184
|
if (builtInNameSet.has(s.name))
|
|
@@ -18059,25 +18198,41 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18059
18198
|
description: s.source === "app" ? buildAppSkillDescription(s.name, registries) || `${s.name} - Runwork workspace application` : `${s.name} - Runwork workspace skill`
|
|
18060
18199
|
}));
|
|
18061
18200
|
const allSkillFiles = [...builtInSkills, ...workspaceSkillFiles];
|
|
18062
|
-
await adapter2.writeSkills(allSkillFiles, scope);
|
|
18063
|
-
|
|
18064
|
-
|
|
18065
|
-
|
|
18066
|
-
|
|
18067
|
-
|
|
18201
|
+
const written = await adapter2.writeSkills(allSkillFiles, scope);
|
|
18202
|
+
if (written > 0) {
|
|
18203
|
+
summary.skillWrites++;
|
|
18204
|
+
summary.skillFilesWritten += written;
|
|
18205
|
+
vlog(` [${adapter2.name}] Wrote ${written} skills (${scope}): ` + `${builtInSkills.length} built-in [${builtInNames.join(", ")}], ` + `${workspaceSkillFiles.length} workspace`);
|
|
18206
|
+
} else {
|
|
18207
|
+
vlog(` [${adapter2.name}] Skipped skills (${scope}): adapter writes none at this scope`);
|
|
18208
|
+
}
|
|
18209
|
+
} catch (err) {
|
|
18210
|
+
adapterFailedAnyScope = true;
|
|
18211
|
+
skillFailedAdapters.add(adapter2.slug);
|
|
18212
|
+
console.warn(` [${adapter2.name}] Failed skills (${scope}): ${err instanceof Error ? err.message : err}`);
|
|
18068
18213
|
}
|
|
18069
|
-
|
|
18214
|
+
} else {
|
|
18215
|
+
vlog(` [${adapter2.name}] Skipped skills (${scope}): adapter does not support skills`);
|
|
18216
|
+
}
|
|
18217
|
+
if (adapter2.supportsMcpScope(scope) && mcpEntries.length > 0) {
|
|
18218
|
+
try {
|
|
18070
18219
|
await adapter2.writeMcpServers(mcpEntries, scope);
|
|
18071
18220
|
summary.mcpServerWrites++;
|
|
18072
|
-
|
|
18073
|
-
}
|
|
18074
|
-
|
|
18075
|
-
|
|
18076
|
-
console.
|
|
18221
|
+
vlog(` [${adapter2.name}] Updated ${mcpEntries.length} MCP server${mcpEntries.length > 1 ? "s" : ""} (${scope})`);
|
|
18222
|
+
} catch (err) {
|
|
18223
|
+
adapterFailedAnyScope = true;
|
|
18224
|
+
mcpFailedAdapters.add(adapter2.slug);
|
|
18225
|
+
console.warn(` [${adapter2.name}] Failed MCP servers (${scope}): ${err instanceof Error ? err.message : err}`);
|
|
18077
18226
|
}
|
|
18227
|
+
} else if (mcpEntries.length === 0) {
|
|
18228
|
+
vlog(` [${adapter2.name}] Skipped MCP servers (${scope}): no workspace MCP servers configured`);
|
|
18229
|
+
} else if (!adapter2.supportsMcpScope(scope)) {
|
|
18230
|
+
vlog(` [${adapter2.name}] Skipped MCP servers (${scope}): adapter does not support MCP at this scope`);
|
|
18231
|
+
}
|
|
18232
|
+
try {
|
|
18078
18233
|
await adapter2.writeInstructionHint(instructionHint, scope);
|
|
18079
18234
|
summary.instructionHintWrites++;
|
|
18080
|
-
|
|
18235
|
+
vlog(` [${adapter2.name}] Updated instruction hints (${scope})`);
|
|
18081
18236
|
if (adapter2.writeBuiltInHooks) {
|
|
18082
18237
|
await adapter2.writeBuiltInHooks(scope);
|
|
18083
18238
|
summary.hookInstallCalls++;
|
|
@@ -18116,7 +18271,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18116
18271
|
try {
|
|
18117
18272
|
await adapter2.writeTeamInstructions(fullInstructions, scope);
|
|
18118
18273
|
teamInstructionsApplied = true;
|
|
18119
|
-
|
|
18274
|
+
vlog(` [${adapter2.name}] Updated team instructions (${scope})`);
|
|
18120
18275
|
} catch {}
|
|
18121
18276
|
}
|
|
18122
18277
|
}
|
|
@@ -18137,7 +18292,7 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18137
18292
|
await adapter2.writeAgentConfig(configWithoutInstructions, scope);
|
|
18138
18293
|
agentConfigsApplied++;
|
|
18139
18294
|
const configKeys = Object.keys(configWithoutInstructions).join(", ");
|
|
18140
|
-
|
|
18295
|
+
vlog(` [${adapter2.name}] Updated agent config: ${configKeys} (${scope})`);
|
|
18141
18296
|
} catch {}
|
|
18142
18297
|
}
|
|
18143
18298
|
}
|
|
@@ -18192,6 +18347,12 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18192
18347
|
try {
|
|
18193
18348
|
const baseline = agentState?.lastInjected;
|
|
18194
18349
|
await adapter2.writeAgentConfig(mergedConfig, "user", baseline);
|
|
18350
|
+
if (baked && !resolved.bootstrapped) {
|
|
18351
|
+
const prev = agentState?.lastInjected;
|
|
18352
|
+
if (!sameStringSet(prev?.allow, resolved.applicableAllow) || !sameStringSet(prev?.deny, resolved.applicableDeny)) {
|
|
18353
|
+
settingsChangedSlugs.push(slug);
|
|
18354
|
+
}
|
|
18355
|
+
}
|
|
18195
18356
|
if (baked) {
|
|
18196
18357
|
const nextState = {
|
|
18197
18358
|
lastInjected: {
|
|
@@ -18205,11 +18366,11 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18205
18366
|
};
|
|
18206
18367
|
state.agentDefaults[slug] = nextState;
|
|
18207
18368
|
if (resolved.bootstrapped) {
|
|
18208
|
-
|
|
18369
|
+
vlog(` [${adapter2.name}] Bootstrapped default-rule tracking (defaults apply on next sync)`);
|
|
18209
18370
|
} else if (resolved.applicableAllow.length || resolved.applicableDeny.length || resolved.removalsThisSync.allow || resolved.removalsThisSync.deny) {
|
|
18210
18371
|
const totalRemovals = resolved.removalsThisSync.allow + resolved.removalsThisSync.deny;
|
|
18211
18372
|
const removalNote = totalRemovals > 0 ? ` (${totalRemovals} new opt-out${totalRemovals > 1 ? "s" : ""} honored)` : "";
|
|
18212
|
-
|
|
18373
|
+
vlog(` [${adapter2.name}] Applied defaults: ${resolved.applicableAllow.length} allow, ${resolved.applicableDeny.length} deny${removalNote}`);
|
|
18213
18374
|
}
|
|
18214
18375
|
}
|
|
18215
18376
|
if (team)
|
|
@@ -18223,11 +18384,12 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18223
18384
|
const runworkDir = join35(homedir17(), ".runwork");
|
|
18224
18385
|
const result = adapter2.registerDesktopWorkspace(runworkDir, "Runwork");
|
|
18225
18386
|
if (result === "written") {
|
|
18226
|
-
|
|
18387
|
+
vlog(` [${adapter2.name}] Registered workspace in Codex desktop app`);
|
|
18227
18388
|
}
|
|
18228
18389
|
break;
|
|
18229
18390
|
}
|
|
18230
18391
|
}
|
|
18392
|
+
const prevMcpNames = state.mcpServers ?? [];
|
|
18231
18393
|
state.lastSyncAt = new Date().toISOString();
|
|
18232
18394
|
state.mcpServers = mcpEntries.map((e) => e.name);
|
|
18233
18395
|
state.skills = remoteSkills.map((s) => s.name);
|
|
@@ -18235,6 +18397,57 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18235
18397
|
"runwork",
|
|
18236
18398
|
...remoteSkills.map((s) => s.name.toLowerCase().replace(/[^a-z0-9]+/g, "-"))
|
|
18237
18399
|
];
|
|
18400
|
+
const priorSkillHashes = state.skillHashes || {};
|
|
18401
|
+
const newLocalHashes = {};
|
|
18402
|
+
for (const [name, h] of Object.entries(newHashes))
|
|
18403
|
+
newLocalHashes[name] = h.localHash;
|
|
18404
|
+
const priorLocalHashes = {};
|
|
18405
|
+
for (const [name, h] of Object.entries(priorSkillHashes))
|
|
18406
|
+
priorLocalHashes[name] = h.localHash;
|
|
18407
|
+
const materializedDeletions = plan.deletions.filter((d) => d.localContent !== undefined).map((d) => d.name);
|
|
18408
|
+
const skillChanges = summarizeRealSkillChanges(newLocalHashes, priorLocalHashes, materializedDeletions);
|
|
18409
|
+
const newMcpNames = mcpEntries.map((e) => e.name);
|
|
18410
|
+
const prevMcpSet = new Set(prevMcpNames);
|
|
18411
|
+
const newMcpSet = new Set(newMcpNames);
|
|
18412
|
+
const mcpAdded = mcpChanged ? newMcpNames.filter((n) => !prevMcpSet.has(n)) : [];
|
|
18413
|
+
const mcpRemoved = mcpChanged ? prevMcpNames.filter((n) => !newMcpSet.has(n)) : [];
|
|
18414
|
+
const addedSet = new Set(addedThisSync);
|
|
18415
|
+
const restartReasons = computeRestartReasons({
|
|
18416
|
+
agents: adapters.map((a) => ({
|
|
18417
|
+
slug: a.slug,
|
|
18418
|
+
receivesMcp: mcpEntries.length > 0 && scopes.some((sc) => a.supportsMcpScope(sc)) && !mcpFailedAdapters.has(a.slug),
|
|
18419
|
+
connectOnly: isConnectOnlyAgent(getRegistryAgent(a.slug)),
|
|
18420
|
+
isNew: !!opts.initialSetup || addedSet.has(a.slug)
|
|
18421
|
+
})),
|
|
18422
|
+
mcpChanged,
|
|
18423
|
+
settingsChangedSlugs
|
|
18424
|
+
});
|
|
18425
|
+
if (Object.keys(restartReasons).length > 0) {
|
|
18426
|
+
if (!state.agentConfigChangedAt)
|
|
18427
|
+
state.agentConfigChangedAt = {};
|
|
18428
|
+
for (const [slug, reasons] of Object.entries(restartReasons)) {
|
|
18429
|
+
state.agentConfigChangedAt[slug] = { changedAt: state.lastSyncAt, reasons };
|
|
18430
|
+
}
|
|
18431
|
+
}
|
|
18432
|
+
if (hasRealSkillChange(skillChanges) || builtInSkillsChanged || mcpChanged || settingsChangedSlugs.length > 0) {
|
|
18433
|
+
state.lastSyncChange = {
|
|
18434
|
+
at: state.lastSyncAt,
|
|
18435
|
+
skills: skillChanges,
|
|
18436
|
+
builtInSkillsChanged,
|
|
18437
|
+
mcp: { changed: mcpChanged, added: mcpAdded, removed: mcpRemoved },
|
|
18438
|
+
settingsSlugs: settingsChangedSlugs
|
|
18439
|
+
};
|
|
18440
|
+
}
|
|
18441
|
+
if (mcpFailedAdapters.size === 0)
|
|
18442
|
+
state.lastMcpEntriesHash = mcpEntriesHash;
|
|
18443
|
+
if (skillFailedAdapters.size === 0)
|
|
18444
|
+
state.builtInSkillsHash = builtInSkillsHash;
|
|
18445
|
+
const nameBySlug = new Map(adapters.map((a) => [a.slug, a.name]));
|
|
18446
|
+
const restartChanges = Object.entries(restartReasons).map(([slug, reasons]) => ({
|
|
18447
|
+
name: nameBySlug.get(slug) ?? slug,
|
|
18448
|
+
reasons
|
|
18449
|
+
}));
|
|
18450
|
+
console.log(` Restart-worthy changes: ${formatRestartChanges(restartChanges)}`);
|
|
18238
18451
|
const mergedHashes = { ...state.skillHashes || {} };
|
|
18239
18452
|
for (const [name, hash] of Object.entries(newHashes)) {
|
|
18240
18453
|
mergedHashes[name] = hash;
|
|
@@ -18256,25 +18469,29 @@ async function syncFromState(state, statePath2, credentials, opts) {
|
|
|
18256
18469
|
if (opts.verbose)
|
|
18257
18470
|
printTelemetryVerbose(telemetry);
|
|
18258
18471
|
await client.reportTelemetry(state.workspaceId, telemetry.events);
|
|
18259
|
-
if (telemetry.healthReported)
|
|
18472
|
+
if (telemetry.healthReported) {
|
|
18260
18473
|
state.lastHealthReportAt = new Date().toISOString();
|
|
18261
|
-
|
|
18262
|
-
|
|
18263
|
-
];
|
|
18264
|
-
writeFileSync29(statePath2, JSON.stringify(state, null, 2));
|
|
18474
|
+
writeFileSync29(statePath2, JSON.stringify(state, null, 2));
|
|
18475
|
+
}
|
|
18265
18476
|
} catch {}
|
|
18266
|
-
const
|
|
18267
|
-
|
|
18268
|
-
|
|
18269
|
-
summaryParts.push(`${summary.
|
|
18270
|
-
|
|
18271
|
-
|
|
18272
|
-
summaryParts.push(`${summary.
|
|
18273
|
-
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
|
|
18477
|
+
const failedNote = summary.adaptersFailed > 0 ? ` (${summary.adaptersFailed} failed)` : "";
|
|
18478
|
+
if (isVerbose()) {
|
|
18479
|
+
const summaryParts = [];
|
|
18480
|
+
summaryParts.push(`${summary.adaptersProcessed} adapter${summary.adaptersProcessed === 1 ? "" : "s"}`);
|
|
18481
|
+
if (summary.adaptersFailed > 0)
|
|
18482
|
+
summaryParts.push(`${summary.adaptersFailed} failed`);
|
|
18483
|
+
summaryParts.push(`${summary.skillWrites} skill write${summary.skillWrites === 1 ? "" : "s"} (${summary.skillFilesWritten} files)`);
|
|
18484
|
+
if (summary.mcpServerWrites > 0)
|
|
18485
|
+
summaryParts.push(`${summary.mcpServerWrites} MCP config write${summary.mcpServerWrites === 1 ? "" : "s"}`);
|
|
18486
|
+
if (summary.hookInstallCalls > 0)
|
|
18487
|
+
summaryParts.push(`${summary.hookInstallCalls} hook install${summary.hookInstallCalls === 1 ? "" : "s"}`);
|
|
18488
|
+
summaryParts.push(`${summary.instructionHintWrites} instruction hint write${summary.instructionHintWrites === 1 ? "" : "s"}`);
|
|
18489
|
+
console.log(`
|
|
18277
18490
|
Summary: ${summaryParts.join(", ")}.`);
|
|
18491
|
+
} else {
|
|
18492
|
+
console.log(`
|
|
18493
|
+
${summary.adaptersProcessed} agent${summary.adaptersProcessed === 1 ? "" : "s"} synced${failedNote}.`);
|
|
18494
|
+
}
|
|
18278
18495
|
try {
|
|
18279
18496
|
const cadence = loadCadenceState();
|
|
18280
18497
|
const lastMs = cadence.lastReflectedAt ? new Date(cadence.lastReflectedAt).getTime() : 0;
|
|
@@ -18467,7 +18684,8 @@ Syncing workspace data...
|
|
|
18467
18684
|
dryRun: false,
|
|
18468
18685
|
pullOnly: true,
|
|
18469
18686
|
yes: true,
|
|
18470
|
-
prefer: "remote"
|
|
18687
|
+
prefer: "remote",
|
|
18688
|
+
initialSetup: true
|
|
18471
18689
|
});
|
|
18472
18690
|
}
|
|
18473
18691
|
console.log("\nSetup complete. Run `runwork sync` anytime to refresh.");
|
package/package.json
CHANGED