@orderful/droid 0.52.1 → 0.53.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/CHANGELOG.md +10 -0
- package/dist/bin/droid.js +83 -3
- package/dist/commands/copy-skills.d.ts +15 -0
- package/dist/commands/copy-skills.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +334 -0
- package/dist/lib/skills.d.ts +23 -0
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/tools/propose-plan/skills/propose-plan/SKILL.md +6 -3
- package/dist/tools/propose-plan/skills/propose-plan/references/output-schema.json +4 -0
- package/package.json +1 -1
- package/src/bin/droid.ts +9 -0
- package/src/commands/copy-skills.ts +66 -0
- package/src/index.ts +2 -0
- package/src/lib/skills.ts +63 -0
- package/src/tools/propose-plan/skills/propose-plan/SKILL.md +6 -3
- package/src/tools/propose-plan/skills/propose-plan/references/output-schema.json +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @orderful/droid
|
|
2
2
|
|
|
3
|
+
## 0.53.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#325](https://github.com/Orderful/droid/pull/325) [`241a9ac`](https://github.com/Orderful/droid/commit/241a9acbfb9864c634fe9f858e19b594d80e83f9) Thanks [@frytyler](https://github.com/frytyler)! - Export tools + pack functions from package entry point and add `droid copy-skills` command for agents integration
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#323](https://github.com/Orderful/droid/pull/323) [`f1459be`](https://github.com/Orderful/droid/commit/f1459beecb6aa72c5fcc6ee552308a3d39f52aad) Thanks [@frytyler](https://github.com/frytyler)! - Add `planSummary` field to propose-plan evidence schema
|
|
12
|
+
|
|
3
13
|
## 0.52.1
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/dist/bin/droid.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/bin/droid.ts
|
|
4
4
|
import { program } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk14 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/commands/setup.ts
|
|
8
8
|
import inquirer from "inquirer";
|
|
@@ -1410,6 +1410,39 @@ function findSkillPath(skillName) {
|
|
|
1410
1410
|
}
|
|
1411
1411
|
return null;
|
|
1412
1412
|
}
|
|
1413
|
+
function getSkillPath(skillName) {
|
|
1414
|
+
const result = findSkillPath(skillName);
|
|
1415
|
+
return result?.skillDir ?? null;
|
|
1416
|
+
}
|
|
1417
|
+
function copySkillsToDir(skillNames, dest) {
|
|
1418
|
+
if (!existsSync7(dest)) {
|
|
1419
|
+
mkdirSync5(dest, { recursive: true });
|
|
1420
|
+
}
|
|
1421
|
+
const results = [];
|
|
1422
|
+
for (const name of skillNames) {
|
|
1423
|
+
const skillDir = getSkillPath(name);
|
|
1424
|
+
if (!skillDir) {
|
|
1425
|
+
results.push({
|
|
1426
|
+
name,
|
|
1427
|
+
success: false,
|
|
1428
|
+
error: `Skill '${name}' not found in bundled tools`
|
|
1429
|
+
});
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
const targetDir = join8(dest, name);
|
|
1433
|
+
try {
|
|
1434
|
+
copyDirectoryRecursive(skillDir, targetDir, () => true);
|
|
1435
|
+
results.push({ name, success: true, dest: targetDir });
|
|
1436
|
+
} catch (err) {
|
|
1437
|
+
results.push({
|
|
1438
|
+
name,
|
|
1439
|
+
success: false,
|
|
1440
|
+
error: `Failed to copy: ${err}`
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
return results;
|
|
1445
|
+
}
|
|
1413
1446
|
function getBundledSkills() {
|
|
1414
1447
|
if (!existsSync7(BUNDLED_SKILLS_DIR)) {
|
|
1415
1448
|
return [];
|
|
@@ -6101,6 +6134,52 @@ async function slackPostCommand(options) {
|
|
|
6101
6134
|
}
|
|
6102
6135
|
}
|
|
6103
6136
|
|
|
6137
|
+
// src/commands/copy-skills.ts
|
|
6138
|
+
import chalk13 from "chalk";
|
|
6139
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
6140
|
+
function copySkillsCommand(options) {
|
|
6141
|
+
const { dest, manifest, names } = options;
|
|
6142
|
+
let skillNames;
|
|
6143
|
+
if (manifest) {
|
|
6144
|
+
try {
|
|
6145
|
+
const content = readFileSync13(manifest, "utf-8");
|
|
6146
|
+
skillNames = JSON.parse(content);
|
|
6147
|
+
if (!Array.isArray(skillNames)) {
|
|
6148
|
+
console.error(
|
|
6149
|
+
chalk13.red("Manifest must be a JSON array of skill names")
|
|
6150
|
+
);
|
|
6151
|
+
process.exit(1);
|
|
6152
|
+
}
|
|
6153
|
+
} catch (err) {
|
|
6154
|
+
console.error(chalk13.red(`Failed to read manifest: ${err}`));
|
|
6155
|
+
process.exit(1);
|
|
6156
|
+
}
|
|
6157
|
+
} else if (names?.length) {
|
|
6158
|
+
skillNames = names;
|
|
6159
|
+
} else {
|
|
6160
|
+
console.error(
|
|
6161
|
+
chalk13.red("Provide either --manifest <file> or --names <names...>")
|
|
6162
|
+
);
|
|
6163
|
+
process.exit(1);
|
|
6164
|
+
}
|
|
6165
|
+
if (skillNames.length === 0) {
|
|
6166
|
+
console.log(chalk13.yellow("No skills to copy."));
|
|
6167
|
+
return;
|
|
6168
|
+
}
|
|
6169
|
+
const results = copySkillsToDir(skillNames, dest);
|
|
6170
|
+
for (const result of results) {
|
|
6171
|
+
if (result.success) {
|
|
6172
|
+
console.log(chalk13.green(` \u2713 ${result.name} \u2192 ${result.dest}`));
|
|
6173
|
+
} else {
|
|
6174
|
+
console.error(chalk13.red(` \u2717 ${result.name}: ${result.error}`));
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
const failed = results.filter((r) => !r.success);
|
|
6178
|
+
if (failed.length > 0) {
|
|
6179
|
+
process.exit(1);
|
|
6180
|
+
}
|
|
6181
|
+
}
|
|
6182
|
+
|
|
6104
6183
|
// src/bin/droid.ts
|
|
6105
6184
|
var version = getVersion();
|
|
6106
6185
|
program.name("droid").description("Droid, teaching your AI new tricks").version(version);
|
|
@@ -6121,6 +6200,7 @@ program.command("update").description("Update droid and installed tools").option
|
|
|
6121
6200
|
program.command("tui").description("Launch interactive TUI dashboard").action(tuiCommand);
|
|
6122
6201
|
program.command("pack").description("Create zip packs for distribution").argument("[audience]", "Target audience (e.g., engineering, customer-support)").option("-l, --list", "List available audiences and tool counts").option("-t, --tool <name>", "Pack a single tool by name").option("-o, --output <dir>", "Output directory (default: cwd)").action(packCommand);
|
|
6123
6202
|
program.command("exec <tool> <script>").description("Execute a tool script").argument("[args...]", "Arguments to pass to the script").allowUnknownOption().action(execCommand);
|
|
6203
|
+
program.command("copy-skills").description("Copy bundled skills to a destination directory").requiredOption("-d, --dest <dir>", "Destination directory").option("-m, --manifest <file>", "JSON file with array of skill names").option("-n, --names <names...>", "Skill names to copy").action(copySkillsCommand);
|
|
6124
6204
|
var integrations = program.command("integrations").description("Manage external service integrations");
|
|
6125
6205
|
var integrationsSetup = integrations.command("setup").description("Set up an integration");
|
|
6126
6206
|
integrationsSetup.command("slack").description("Set up Slack integration").action(integrationsSetupSlackCommand);
|
|
@@ -6132,8 +6212,8 @@ if (configExists()) {
|
|
|
6132
6212
|
const config = loadConfig();
|
|
6133
6213
|
const newPlatforms = syncNewPlatforms(config);
|
|
6134
6214
|
if (newPlatforms.length > 0) {
|
|
6135
|
-
console.log(
|
|
6136
|
-
console.log(
|
|
6215
|
+
console.log(chalk14.green(`\u2713 Detected new platform(s): ${newPlatforms.join(", ")}`));
|
|
6216
|
+
console.log(chalk14.gray(" Synced installed tools to new platform(s)\n"));
|
|
6137
6217
|
saveConfig(config);
|
|
6138
6218
|
}
|
|
6139
6219
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface CopySkillsOptions {
|
|
2
|
+
dest: string;
|
|
3
|
+
manifest?: string;
|
|
4
|
+
names?: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Copy bundled skills to a destination directory.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* droid copy-skills -d dist/assets/skills -m droid-skills.json
|
|
11
|
+
* droid copy-skills -d dist/assets/skills -n propose-plan edi-schema
|
|
12
|
+
*/
|
|
13
|
+
export declare function copySkillsCommand(options: CopySkillsOptions): void;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=copy-skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-skills.d.ts","sourceRoot":"","sources":["../../src/commands/copy-skills.ts"],"names":[],"mappings":"AAIA,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAgDlE"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -602,6 +602,9 @@ async function checkForUpdates() {
|
|
|
602
602
|
// src/lib/tools.ts
|
|
603
603
|
var __dirname2 = dirname3(fileURLToPath2(import.meta.url));
|
|
604
604
|
var BUNDLED_TOOLS_DIR = join5(__dirname2, "../tools");
|
|
605
|
+
function getBundledToolsDir() {
|
|
606
|
+
return BUNDLED_TOOLS_DIR;
|
|
607
|
+
}
|
|
605
608
|
function loadToolManifest(toolDir) {
|
|
606
609
|
const manifestPath = join5(toolDir, "TOOL.yaml");
|
|
607
610
|
if (!existsSync4(manifestPath)) {
|
|
@@ -645,6 +648,58 @@ function isToolInstalled(toolName) {
|
|
|
645
648
|
const requiredSkills = tool.includes.skills.filter((s) => s.required).map((s) => s.name);
|
|
646
649
|
return requiredSkills.some((skillName) => skillName in installedTools);
|
|
647
650
|
}
|
|
651
|
+
function getInstalledToolVersion(toolName) {
|
|
652
|
+
const config = loadConfig();
|
|
653
|
+
const installedTools = getPlatformTools(config);
|
|
654
|
+
const tool = getBundledTools().find((t) => t.name === toolName);
|
|
655
|
+
if (!tool) return null;
|
|
656
|
+
const requiredSkills = tool.includes.skills.filter((s) => s.required).map((s) => s.name);
|
|
657
|
+
for (const skillName of requiredSkills) {
|
|
658
|
+
if (installedTools[skillName]) {
|
|
659
|
+
return installedTools[skillName].version;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
function getToolUpdateStatus(toolName) {
|
|
665
|
+
const installedVersion = getInstalledToolVersion(toolName);
|
|
666
|
+
const tool = getBundledTools().find((t) => t.name === toolName);
|
|
667
|
+
const bundledVersion = tool?.version || null;
|
|
668
|
+
if (!installedVersion || !bundledVersion) {
|
|
669
|
+
return {
|
|
670
|
+
name: toolName,
|
|
671
|
+
hasUpdate: false,
|
|
672
|
+
installedVersion,
|
|
673
|
+
bundledVersion
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
const hasUpdate = compareSemver(bundledVersion, installedVersion) > 0;
|
|
677
|
+
return {
|
|
678
|
+
name: toolName,
|
|
679
|
+
hasUpdate,
|
|
680
|
+
installedVersion,
|
|
681
|
+
bundledVersion
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function getToolsWithUpdates() {
|
|
685
|
+
const config = loadConfig();
|
|
686
|
+
const installedTools = getPlatformTools(config);
|
|
687
|
+
const bundledTools = getBundledTools();
|
|
688
|
+
const toolsWithUpdates = [];
|
|
689
|
+
for (const tool of bundledTools) {
|
|
690
|
+
const requiredSkills = tool.includes.skills.filter((s) => s.required).map((s) => s.name);
|
|
691
|
+
const isInstalled = requiredSkills.some(
|
|
692
|
+
(skillName) => skillName in installedTools
|
|
693
|
+
);
|
|
694
|
+
if (isInstalled) {
|
|
695
|
+
const updateStatus = getToolUpdateStatus(tool.name);
|
|
696
|
+
if (updateStatus.hasUpdate) {
|
|
697
|
+
toolsWithUpdates.push(updateStatus);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return toolsWithUpdates;
|
|
702
|
+
}
|
|
648
703
|
|
|
649
704
|
// src/lib/agents.ts
|
|
650
705
|
var __dirname3 = dirname4(fileURLToPath3(import.meta.url));
|
|
@@ -1316,6 +1371,39 @@ function findSkillPath(skillName) {
|
|
|
1316
1371
|
}
|
|
1317
1372
|
return null;
|
|
1318
1373
|
}
|
|
1374
|
+
function getSkillPath(skillName) {
|
|
1375
|
+
const result = findSkillPath(skillName);
|
|
1376
|
+
return result?.skillDir ?? null;
|
|
1377
|
+
}
|
|
1378
|
+
function copySkillsToDir(skillNames, dest) {
|
|
1379
|
+
if (!existsSync7(dest)) {
|
|
1380
|
+
mkdirSync5(dest, { recursive: true });
|
|
1381
|
+
}
|
|
1382
|
+
const results = [];
|
|
1383
|
+
for (const name of skillNames) {
|
|
1384
|
+
const skillDir = getSkillPath(name);
|
|
1385
|
+
if (!skillDir) {
|
|
1386
|
+
results.push({
|
|
1387
|
+
name,
|
|
1388
|
+
success: false,
|
|
1389
|
+
error: `Skill '${name}' not found in bundled tools`
|
|
1390
|
+
});
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
const targetDir = join8(dest, name);
|
|
1394
|
+
try {
|
|
1395
|
+
copyDirectoryRecursive(skillDir, targetDir, () => true);
|
|
1396
|
+
results.push({ name, success: true, dest: targetDir });
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
results.push({
|
|
1399
|
+
name,
|
|
1400
|
+
success: false,
|
|
1401
|
+
error: `Failed to copy: ${err}`
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return results;
|
|
1406
|
+
}
|
|
1319
1407
|
function getBundledSkills() {
|
|
1320
1408
|
if (!existsSync7(BUNDLED_SKILLS_DIR)) {
|
|
1321
1409
|
return [];
|
|
@@ -1822,6 +1910,239 @@ function uninstallCommand(commandName, skillName) {
|
|
|
1822
1910
|
}
|
|
1823
1911
|
return { success: false, message: `Command not installed: ${commandName}` };
|
|
1824
1912
|
}
|
|
1913
|
+
|
|
1914
|
+
// src/lib/pack.ts
|
|
1915
|
+
import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync7, createWriteStream } from "fs";
|
|
1916
|
+
import { join as join9 } from "path";
|
|
1917
|
+
import archiver from "archiver";
|
|
1918
|
+
function getToolsForAudience(audience) {
|
|
1919
|
+
const allTools = getBundledTools();
|
|
1920
|
+
return allTools.filter((tool) => {
|
|
1921
|
+
if (!tool.audience || tool.audience.length === 0) {
|
|
1922
|
+
return false;
|
|
1923
|
+
}
|
|
1924
|
+
return tool.audience.includes(audience) || tool.audience.includes("all" /* All */);
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
function getAudienceInfo() {
|
|
1928
|
+
const allTools = getBundledTools();
|
|
1929
|
+
const audiences = Object.values(ToolAudience).filter(
|
|
1930
|
+
(a) => a !== "all" /* All */
|
|
1931
|
+
);
|
|
1932
|
+
return audiences.map((audience) => {
|
|
1933
|
+
const tools = allTools.filter(
|
|
1934
|
+
(tool) => tool.audience && (tool.audience.includes(audience) || tool.audience.includes("all" /* All */))
|
|
1935
|
+
);
|
|
1936
|
+
return {
|
|
1937
|
+
audience,
|
|
1938
|
+
toolCount: tools.length,
|
|
1939
|
+
toolNames: tools.map((t) => t.name)
|
|
1940
|
+
};
|
|
1941
|
+
}).filter((info) => info.toolCount > 0);
|
|
1942
|
+
}
|
|
1943
|
+
function collectToolArtifacts(tool) {
|
|
1944
|
+
const artifacts = [];
|
|
1945
|
+
const toolDir = join9(getBundledToolsDir(), tool.name);
|
|
1946
|
+
for (const skill of tool.includes.skills) {
|
|
1947
|
+
const skillDir = join9(toolDir, "skills", skill.name);
|
|
1948
|
+
if (!existsSync8(skillDir)) continue;
|
|
1949
|
+
const skillMd = join9(skillDir, "SKILL.md");
|
|
1950
|
+
if (existsSync8(skillMd)) {
|
|
1951
|
+
artifacts.push({
|
|
1952
|
+
sourcePath: skillMd,
|
|
1953
|
+
zipPath: `skills/${skill.name}/SKILL.md`
|
|
1954
|
+
});
|
|
1955
|
+
}
|
|
1956
|
+
const refsDir = join9(skillDir, "references");
|
|
1957
|
+
if (existsSync8(refsDir)) {
|
|
1958
|
+
const refFiles = readdirSync7(refsDir).filter((f) => !f.startsWith("."));
|
|
1959
|
+
for (const file of refFiles) {
|
|
1960
|
+
artifacts.push({
|
|
1961
|
+
sourcePath: join9(refsDir, file),
|
|
1962
|
+
zipPath: `skills/${skill.name}/references/${file}`
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
const commandsDir = join9(toolDir, "commands");
|
|
1968
|
+
if (existsSync8(commandsDir)) {
|
|
1969
|
+
const commandFiles = readdirSync7(commandsDir).filter(
|
|
1970
|
+
(f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
|
|
1971
|
+
);
|
|
1972
|
+
for (const file of commandFiles) {
|
|
1973
|
+
artifacts.push({
|
|
1974
|
+
sourcePath: join9(commandsDir, file),
|
|
1975
|
+
zipPath: `commands/${file}`
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
const agentsDir = join9(toolDir, "agents");
|
|
1980
|
+
if (existsSync8(agentsDir)) {
|
|
1981
|
+
const agentFiles = readdirSync7(agentsDir).filter(
|
|
1982
|
+
(f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md"
|
|
1983
|
+
);
|
|
1984
|
+
for (const file of agentFiles) {
|
|
1985
|
+
artifacts.push({
|
|
1986
|
+
sourcePath: join9(agentsDir, file),
|
|
1987
|
+
zipPath: `agents/${file}`
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
return artifacts;
|
|
1992
|
+
}
|
|
1993
|
+
function generateClaudeMd(tools) {
|
|
1994
|
+
const skillNames = [];
|
|
1995
|
+
for (const tool of tools) {
|
|
1996
|
+
for (const skill of tool.includes.skills) {
|
|
1997
|
+
skillNames.push(skill.name);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
const lines = [
|
|
2001
|
+
"# Droid Skills",
|
|
2002
|
+
"",
|
|
2003
|
+
"Skills installed from a Droid pack. Each skill teaches your AI new capabilities.",
|
|
2004
|
+
""
|
|
2005
|
+
];
|
|
2006
|
+
for (const name of skillNames) {
|
|
2007
|
+
lines.push(`- [${name}](skills/${name}/SKILL.md)`);
|
|
2008
|
+
}
|
|
2009
|
+
lines.push("");
|
|
2010
|
+
return lines.join("\n");
|
|
2011
|
+
}
|
|
2012
|
+
function generateReadme(label, tools) {
|
|
2013
|
+
const lines = [
|
|
2014
|
+
`# Droid Pack: ${label}`,
|
|
2015
|
+
"",
|
|
2016
|
+
"This pack contains AI skills, commands, and agents for Claude Desktop.",
|
|
2017
|
+
"",
|
|
2018
|
+
"## Installation",
|
|
2019
|
+
"",
|
|
2020
|
+
"1. Unzip this archive",
|
|
2021
|
+
"2. Copy the contents into your `~/.claude/` directory:",
|
|
2022
|
+
"",
|
|
2023
|
+
"```bash",
|
|
2024
|
+
"# From the directory where you unzipped:",
|
|
2025
|
+
"cp -r skills/ ~/.claude/skills/",
|
|
2026
|
+
"cp -r commands/ ~/.claude/commands/",
|
|
2027
|
+
"cp -r agents/ ~/.claude/agents/",
|
|
2028
|
+
"```",
|
|
2029
|
+
"",
|
|
2030
|
+
"3. Append the contents of `CLAUDE.md` to your `~/.claude/CLAUDE.md`:",
|
|
2031
|
+
"",
|
|
2032
|
+
"```bash",
|
|
2033
|
+
"cat CLAUDE.md >> ~/.claude/CLAUDE.md",
|
|
2034
|
+
"```",
|
|
2035
|
+
"",
|
|
2036
|
+
"## Included Tools",
|
|
2037
|
+
""
|
|
2038
|
+
];
|
|
2039
|
+
for (const tool of tools) {
|
|
2040
|
+
lines.push(`- **${tool.name}** (v${tool.version}) \u2014 ${tool.description}`);
|
|
2041
|
+
}
|
|
2042
|
+
lines.push("");
|
|
2043
|
+
return lines.join("\n");
|
|
2044
|
+
}
|
|
2045
|
+
function checkDependencies(tools) {
|
|
2046
|
+
const warnings = [];
|
|
2047
|
+
const toolNames = new Set(tools.map((t) => t.name));
|
|
2048
|
+
for (const tool of tools) {
|
|
2049
|
+
if (!tool.dependencies) continue;
|
|
2050
|
+
for (const dep of tool.dependencies) {
|
|
2051
|
+
if (!toolNames.has(dep)) {
|
|
2052
|
+
warnings.push(
|
|
2053
|
+
`Tool '${tool.name}' depends on '${dep}' which is not included in this pack`
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
return warnings;
|
|
2059
|
+
}
|
|
2060
|
+
async function buildToolPack(options) {
|
|
2061
|
+
const { toolName, outputDir } = options;
|
|
2062
|
+
const allTools = getBundledTools();
|
|
2063
|
+
const tool = allTools.find((t) => t.name === toolName);
|
|
2064
|
+
if (!tool) {
|
|
2065
|
+
return {
|
|
2066
|
+
success: false,
|
|
2067
|
+
message: `Tool '${toolName}' not found`
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
const tools = [tool];
|
|
2071
|
+
const warnings = checkDependencies(tools);
|
|
2072
|
+
const filename = `droid-${toolName}.zip`;
|
|
2073
|
+
const outputPath = join9(outputDir, filename);
|
|
2074
|
+
return new Promise((resolve) => {
|
|
2075
|
+
const output = createWriteStream(outputPath);
|
|
2076
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
2077
|
+
output.on("close", () => {
|
|
2078
|
+
resolve({
|
|
2079
|
+
success: true,
|
|
2080
|
+
message: `Pack created: ${filename}`,
|
|
2081
|
+
outputPath,
|
|
2082
|
+
toolCount: 1,
|
|
2083
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
2084
|
+
});
|
|
2085
|
+
});
|
|
2086
|
+
archive.on("error", (err) => {
|
|
2087
|
+
resolve({
|
|
2088
|
+
success: false,
|
|
2089
|
+
message: `Failed to create pack: ${err.message}`
|
|
2090
|
+
});
|
|
2091
|
+
});
|
|
2092
|
+
archive.pipe(output);
|
|
2093
|
+
const artifacts = collectToolArtifacts(tool);
|
|
2094
|
+
for (const artifact of artifacts) {
|
|
2095
|
+
const content = readFileSync7(artifact.sourcePath, "utf-8");
|
|
2096
|
+
archive.append(content, { name: artifact.zipPath });
|
|
2097
|
+
}
|
|
2098
|
+
archive.append(generateClaudeMd(tools), { name: "CLAUDE.md" });
|
|
2099
|
+
archive.append(generateReadme(toolName, tools), { name: "README.md" });
|
|
2100
|
+
archive.finalize();
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
async function buildPack(options) {
|
|
2104
|
+
const { audience, outputDir } = options;
|
|
2105
|
+
const tools = getToolsForAudience(audience);
|
|
2106
|
+
if (tools.length === 0) {
|
|
2107
|
+
return {
|
|
2108
|
+
success: false,
|
|
2109
|
+
message: `No tools found for audience '${audience}'`
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
const warnings = checkDependencies(tools);
|
|
2113
|
+
const filename = `droid-${audience}-pack.zip`;
|
|
2114
|
+
const outputPath = join9(outputDir, filename);
|
|
2115
|
+
return new Promise((resolve) => {
|
|
2116
|
+
const output = createWriteStream(outputPath);
|
|
2117
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
2118
|
+
output.on("close", () => {
|
|
2119
|
+
resolve({
|
|
2120
|
+
success: true,
|
|
2121
|
+
message: `Pack created: ${filename}`,
|
|
2122
|
+
outputPath,
|
|
2123
|
+
toolCount: tools.length,
|
|
2124
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
2125
|
+
});
|
|
2126
|
+
});
|
|
2127
|
+
archive.on("error", (err) => {
|
|
2128
|
+
resolve({
|
|
2129
|
+
success: false,
|
|
2130
|
+
message: `Failed to create pack: ${err.message}`
|
|
2131
|
+
});
|
|
2132
|
+
});
|
|
2133
|
+
archive.pipe(output);
|
|
2134
|
+
for (const tool of tools) {
|
|
2135
|
+
const artifacts = collectToolArtifacts(tool);
|
|
2136
|
+
for (const artifact of artifacts) {
|
|
2137
|
+
const content = readFileSync7(artifact.sourcePath, "utf-8");
|
|
2138
|
+
archive.append(content, { name: artifact.zipPath });
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
archive.append(generateClaudeMd(tools), { name: "CLAUDE.md" });
|
|
2142
|
+
archive.append(generateReadme(audience, tools), { name: "README.md" });
|
|
2143
|
+
archive.finalize();
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
1825
2146
|
export {
|
|
1826
2147
|
AIToolValue as AITool,
|
|
1827
2148
|
BuiltInOutput,
|
|
@@ -1830,20 +2151,27 @@ export {
|
|
|
1830
2151
|
SkillStatus,
|
|
1831
2152
|
ToolAudience,
|
|
1832
2153
|
addRepo,
|
|
2154
|
+
buildPack,
|
|
2155
|
+
buildToolPack,
|
|
1833
2156
|
checkForUpdates,
|
|
1834
2157
|
compareSemver,
|
|
1835
2158
|
configExists,
|
|
2159
|
+
copySkillsToDir,
|
|
1836
2160
|
ensureConfigDir,
|
|
1837
2161
|
findSkillPath,
|
|
1838
2162
|
getAITag,
|
|
2163
|
+
getAudienceInfo,
|
|
1839
2164
|
getAutoUpdateConfig,
|
|
1840
2165
|
getBundledSkills,
|
|
1841
2166
|
getBundledSkillsDir,
|
|
2167
|
+
getBundledTools,
|
|
2168
|
+
getBundledToolsDir,
|
|
1842
2169
|
getCommandsInstallPath,
|
|
1843
2170
|
getConfigDir,
|
|
1844
2171
|
getConfigPath,
|
|
1845
2172
|
getConfigValue,
|
|
1846
2173
|
getInstalledSkill,
|
|
2174
|
+
getInstalledToolVersion,
|
|
1847
2175
|
getPlatformConfigPath,
|
|
1848
2176
|
getPlatformTools,
|
|
1849
2177
|
getPlatformToolsFor,
|
|
@@ -1851,20 +2179,26 @@ export {
|
|
|
1851
2179
|
getRepoPath,
|
|
1852
2180
|
getRepos,
|
|
1853
2181
|
getSkillOverridesPath,
|
|
2182
|
+
getSkillPath,
|
|
1854
2183
|
getSkillStatusDisplay,
|
|
1855
2184
|
getSkillUpdateStatus,
|
|
1856
2185
|
getSkillsInstallPath,
|
|
1857
2186
|
getSkillsWithUpdates,
|
|
1858
2187
|
getToolSettings,
|
|
2188
|
+
getToolUpdateStatus,
|
|
2189
|
+
getToolsForAudience,
|
|
2190
|
+
getToolsWithUpdates,
|
|
1859
2191
|
getUpdateInfo,
|
|
1860
2192
|
getVersion,
|
|
1861
2193
|
installCommand,
|
|
1862
2194
|
installSkill,
|
|
1863
2195
|
isCommandInstalled,
|
|
1864
2196
|
isSkillInstalled,
|
|
2197
|
+
isToolInstalled,
|
|
1865
2198
|
loadConfig,
|
|
1866
2199
|
loadSkillManifest,
|
|
1867
2200
|
loadSkillOverrides,
|
|
2201
|
+
loadToolManifest,
|
|
1868
2202
|
removeRepo,
|
|
1869
2203
|
runUpdate,
|
|
1870
2204
|
saveConfig,
|
package/dist/lib/skills.d.ts
CHANGED
|
@@ -34,6 +34,29 @@ export declare function findSkillPath(skillName: string): {
|
|
|
34
34
|
toolDir: string;
|
|
35
35
|
skillDir: string;
|
|
36
36
|
} | null;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the absolute path to a bundled skill directory by name.
|
|
39
|
+
* Returns null if the skill is not found.
|
|
40
|
+
*
|
|
41
|
+
* This is the stable public API for consumers who need to locate skill
|
|
42
|
+
* assets (e.g., for copying into a build output). It encapsulates droid's
|
|
43
|
+
* internal `tools/{tool}/skills/{name}/` directory structure.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getSkillPath(skillName: string): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Copy bundled skills to a destination directory.
|
|
48
|
+
* Each skill is copied as `{dest}/{skillName}/` with SKILL.md, references/, etc.
|
|
49
|
+
*
|
|
50
|
+
* @param skillNames - Array of skill names to copy
|
|
51
|
+
* @param dest - Target directory (created if it doesn't exist)
|
|
52
|
+
* @returns Results per skill: success/failure with paths
|
|
53
|
+
*/
|
|
54
|
+
export declare function copySkillsToDir(skillNames: string[], dest: string): Array<{
|
|
55
|
+
name: string;
|
|
56
|
+
success: boolean;
|
|
57
|
+
dest?: string;
|
|
58
|
+
error?: string;
|
|
59
|
+
}>;
|
|
37
60
|
/**
|
|
38
61
|
* Get all bundled skills from all tools
|
|
39
62
|
*/
|
package/dist/lib/skills.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,7 @@ Produce a single JSON object matching the schema in `references/output-schema.js
|
|
|
32
32
|
"name": "string — short human-readable plan name (optional)",
|
|
33
33
|
"category": "string — grouping category, e.g. org-provisioning (optional)",
|
|
34
34
|
"evidence": {
|
|
35
|
+
"planSummary": "string — one-line plain-language summary, e.g. 'Provision org and billing for Acme Corp' (optional)",
|
|
35
36
|
"reasoning": "string — your analysis of what needs to happen and why",
|
|
36
37
|
"sourceSummary": "string — concise summary of what you found during research",
|
|
37
38
|
"sourceRaw": "string — JSON-stringified raw source data from research (optional)",
|
|
@@ -53,9 +54,10 @@ Produce a single JSON object matching the schema in `references/output-schema.js
|
|
|
53
54
|
|
|
54
55
|
### Evidence Fields
|
|
55
56
|
|
|
56
|
-
| Field | Purpose
|
|
57
|
-
| --------------- |
|
|
58
|
-
| `
|
|
57
|
+
| Field | Purpose | Reviewer Experience |
|
|
58
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
59
|
+
| `planSummary` | Optional. One-line plain-language summary of the plan. Keep it short and specific — entity names, not jargon. | Shown in headers and card previews. Quick scan context. |
|
|
60
|
+
| `reasoning` | Your analysis — what needs to happen and why. Cite actual data from your research, not assumptions. | First thing they read. Establishes trust. |
|
|
59
61
|
| `sourceSummary` | Concise summary of what you found. Include entity names, IDs, and states. | Quick scan to verify you looked at the right things. |
|
|
60
62
|
| `sourceRaw` | Optional. JSON-stringified raw API responses or data snapshots. | Expandable detail for reviewers who want to verify. |
|
|
61
63
|
| `impactSummary` | What changes if the plan is approved. Be specific — "creates org X with ISA ID Y" not "creates an org". | The core decision point. Reviewer approves based on this. |
|
|
@@ -129,6 +131,7 @@ Say you've been asked to provision an Orderful org for a new customer. You've qu
|
|
|
129
131
|
```json
|
|
130
132
|
{
|
|
131
133
|
"evidence": {
|
|
134
|
+
"planSummary": "Provision org, billing, and welcome email for Acme Corp",
|
|
132
135
|
"reasoning": "Salesforce account Acme Corp (SF-001234) was signed on 2026-03-01 and has no Orderful OrgID. No existing Orderful org matches by name or ISA ID. The account's primary contact is jane@acme.com. ISA ID derived from Customer_ISA_ID__c field: ACME001.",
|
|
133
136
|
"sourceSummary": "Salesforce: Acme Corp (SF-001234), signed 2026-03-01, no OrgID. Orderful: no org named 'Acme Corp', no ISA ID 'ACME001' in use.",
|
|
134
137
|
"sourceRaw": "{\"salesforce_account\":{\"Id\":\"SF-001234\",\"Name\":\"Acme Corp\",\"OrgID__c\":null,\"Customer_ISA_ID__c\":\"ACME001\"},\"orderful_org_search\":{\"results\":[]}}",
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"description": "Research findings and rationale supporting the plan",
|
|
19
19
|
"required": ["reasoning", "sourceSummary", "impactSummary"],
|
|
20
20
|
"properties": {
|
|
21
|
+
"planSummary": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "One-line plain-language summary of the plan"
|
|
24
|
+
},
|
|
21
25
|
"reasoning": {
|
|
22
26
|
"type": "string",
|
|
23
27
|
"description": "Analysis of what needs to happen and why"
|
package/package.json
CHANGED
package/src/bin/droid.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { integrationsSetupSlackCommand, integrationsStatusCommand, slackPostComm
|
|
|
21
21
|
import { getVersion } from '../lib/version';
|
|
22
22
|
import { loadConfig, saveConfig, configExists } from '../lib/config';
|
|
23
23
|
import { syncNewPlatforms } from '../lib/platforms';
|
|
24
|
+
import { copySkillsCommand } from '../commands/copy-skills';
|
|
24
25
|
|
|
25
26
|
const version = getVersion();
|
|
26
27
|
|
|
@@ -120,6 +121,14 @@ program
|
|
|
120
121
|
.allowUnknownOption()
|
|
121
122
|
.action(execCommand);
|
|
122
123
|
|
|
124
|
+
program
|
|
125
|
+
.command('copy-skills')
|
|
126
|
+
.description('Copy bundled skills to a destination directory')
|
|
127
|
+
.requiredOption('-d, --dest <dir>', 'Destination directory')
|
|
128
|
+
.option('-m, --manifest <file>', 'JSON file with array of skill names')
|
|
129
|
+
.option('-n, --names <names...>', 'Skill names to copy')
|
|
130
|
+
.action(copySkillsCommand);
|
|
131
|
+
|
|
123
132
|
// Integrations command with subcommands
|
|
124
133
|
const integrations = program
|
|
125
134
|
.command('integrations')
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { copySkillsToDir } from '../lib/skills';
|
|
4
|
+
|
|
5
|
+
interface CopySkillsOptions {
|
|
6
|
+
dest: string;
|
|
7
|
+
manifest?: string;
|
|
8
|
+
names?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Copy bundled skills to a destination directory.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* droid copy-skills -d dist/assets/skills -m droid-skills.json
|
|
16
|
+
* droid copy-skills -d dist/assets/skills -n propose-plan edi-schema
|
|
17
|
+
*/
|
|
18
|
+
export function copySkillsCommand(options: CopySkillsOptions): void {
|
|
19
|
+
const { dest, manifest, names } = options;
|
|
20
|
+
|
|
21
|
+
// Resolve skill names from manifest file or --names flag
|
|
22
|
+
let skillNames: string[];
|
|
23
|
+
|
|
24
|
+
if (manifest) {
|
|
25
|
+
try {
|
|
26
|
+
const content = readFileSync(manifest, 'utf-8');
|
|
27
|
+
skillNames = JSON.parse(content);
|
|
28
|
+
if (!Array.isArray(skillNames)) {
|
|
29
|
+
console.error(
|
|
30
|
+
chalk.red('Manifest must be a JSON array of skill names'),
|
|
31
|
+
);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error(chalk.red(`Failed to read manifest: ${err}`));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
} else if (names?.length) {
|
|
39
|
+
skillNames = names;
|
|
40
|
+
} else {
|
|
41
|
+
console.error(
|
|
42
|
+
chalk.red('Provide either --manifest <file> or --names <names...>'),
|
|
43
|
+
);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (skillNames.length === 0) {
|
|
48
|
+
console.log(chalk.yellow('No skills to copy.'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const results = copySkillsToDir(skillNames, dest);
|
|
53
|
+
|
|
54
|
+
for (const result of results) {
|
|
55
|
+
if (result.success) {
|
|
56
|
+
console.log(chalk.green(` ✓ ${result.name} → ${result.dest}`));
|
|
57
|
+
} else {
|
|
58
|
+
console.error(chalk.red(` ✗ ${result.name}: ${result.error}`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const failed = results.filter((r) => !r.success);
|
|
63
|
+
if (failed.length > 0) {
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/index.ts
CHANGED
package/src/lib/skills.ts
CHANGED
|
@@ -213,6 +213,69 @@ export function findSkillPath(
|
|
|
213
213
|
return null;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Resolve the absolute path to a bundled skill directory by name.
|
|
218
|
+
* Returns null if the skill is not found.
|
|
219
|
+
*
|
|
220
|
+
* This is the stable public API for consumers who need to locate skill
|
|
221
|
+
* assets (e.g., for copying into a build output). It encapsulates droid's
|
|
222
|
+
* internal `tools/{tool}/skills/{name}/` directory structure.
|
|
223
|
+
*/
|
|
224
|
+
export function getSkillPath(skillName: string): string | null {
|
|
225
|
+
const result = findSkillPath(skillName);
|
|
226
|
+
return result?.skillDir ?? null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Copy bundled skills to a destination directory.
|
|
231
|
+
* Each skill is copied as `{dest}/{skillName}/` with SKILL.md, references/, etc.
|
|
232
|
+
*
|
|
233
|
+
* @param skillNames - Array of skill names to copy
|
|
234
|
+
* @param dest - Target directory (created if it doesn't exist)
|
|
235
|
+
* @returns Results per skill: success/failure with paths
|
|
236
|
+
*/
|
|
237
|
+
export function copySkillsToDir(
|
|
238
|
+
skillNames: string[],
|
|
239
|
+
dest: string,
|
|
240
|
+
): Array<{ name: string; success: boolean; dest?: string; error?: string }> {
|
|
241
|
+
if (!existsSync(dest)) {
|
|
242
|
+
mkdirSync(dest, { recursive: true });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const results: Array<{
|
|
246
|
+
name: string;
|
|
247
|
+
success: boolean;
|
|
248
|
+
dest?: string;
|
|
249
|
+
error?: string;
|
|
250
|
+
}> = [];
|
|
251
|
+
|
|
252
|
+
for (const name of skillNames) {
|
|
253
|
+
const skillDir = getSkillPath(name);
|
|
254
|
+
if (!skillDir) {
|
|
255
|
+
results.push({
|
|
256
|
+
name,
|
|
257
|
+
success: false,
|
|
258
|
+
error: `Skill '${name}' not found in bundled tools`,
|
|
259
|
+
});
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const targetDir = join(dest, name);
|
|
264
|
+
try {
|
|
265
|
+
copyDirectoryRecursive(skillDir, targetDir, () => true);
|
|
266
|
+
results.push({ name, success: true, dest: targetDir });
|
|
267
|
+
} catch (err) {
|
|
268
|
+
results.push({
|
|
269
|
+
name,
|
|
270
|
+
success: false,
|
|
271
|
+
error: `Failed to copy: ${err}`,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return results;
|
|
277
|
+
}
|
|
278
|
+
|
|
216
279
|
/**
|
|
217
280
|
* Get all bundled skills from all tools
|
|
218
281
|
*/
|
|
@@ -32,6 +32,7 @@ Produce a single JSON object matching the schema in `references/output-schema.js
|
|
|
32
32
|
"name": "string — short human-readable plan name (optional)",
|
|
33
33
|
"category": "string — grouping category, e.g. org-provisioning (optional)",
|
|
34
34
|
"evidence": {
|
|
35
|
+
"planSummary": "string — one-line plain-language summary, e.g. 'Provision org and billing for Acme Corp' (optional)",
|
|
35
36
|
"reasoning": "string — your analysis of what needs to happen and why",
|
|
36
37
|
"sourceSummary": "string — concise summary of what you found during research",
|
|
37
38
|
"sourceRaw": "string — JSON-stringified raw source data from research (optional)",
|
|
@@ -53,9 +54,10 @@ Produce a single JSON object matching the schema in `references/output-schema.js
|
|
|
53
54
|
|
|
54
55
|
### Evidence Fields
|
|
55
56
|
|
|
56
|
-
| Field | Purpose
|
|
57
|
-
| --------------- |
|
|
58
|
-
| `
|
|
57
|
+
| Field | Purpose | Reviewer Experience |
|
|
58
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
59
|
+
| `planSummary` | Optional. One-line plain-language summary of the plan. Keep it short and specific — entity names, not jargon. | Shown in headers and card previews. Quick scan context. |
|
|
60
|
+
| `reasoning` | Your analysis — what needs to happen and why. Cite actual data from your research, not assumptions. | First thing they read. Establishes trust. |
|
|
59
61
|
| `sourceSummary` | Concise summary of what you found. Include entity names, IDs, and states. | Quick scan to verify you looked at the right things. |
|
|
60
62
|
| `sourceRaw` | Optional. JSON-stringified raw API responses or data snapshots. | Expandable detail for reviewers who want to verify. |
|
|
61
63
|
| `impactSummary` | What changes if the plan is approved. Be specific — "creates org X with ISA ID Y" not "creates an org". | The core decision point. Reviewer approves based on this. |
|
|
@@ -129,6 +131,7 @@ Say you've been asked to provision an Orderful org for a new customer. You've qu
|
|
|
129
131
|
```json
|
|
130
132
|
{
|
|
131
133
|
"evidence": {
|
|
134
|
+
"planSummary": "Provision org, billing, and welcome email for Acme Corp",
|
|
132
135
|
"reasoning": "Salesforce account Acme Corp (SF-001234) was signed on 2026-03-01 and has no Orderful OrgID. No existing Orderful org matches by name or ISA ID. The account's primary contact is jane@acme.com. ISA ID derived from Customer_ISA_ID__c field: ACME001.",
|
|
133
136
|
"sourceSummary": "Salesforce: Acme Corp (SF-001234), signed 2026-03-01, no OrgID. Orderful: no org named 'Acme Corp', no ISA ID 'ACME001' in use.",
|
|
134
137
|
"sourceRaw": "{\"salesforce_account\":{\"Id\":\"SF-001234\",\"Name\":\"Acme Corp\",\"OrgID__c\":null,\"Customer_ISA_ID__c\":\"ACME001\"},\"orderful_org_search\":{\"results\":[]}}",
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"description": "Research findings and rationale supporting the plan",
|
|
19
19
|
"required": ["reasoning", "sourceSummary", "impactSummary"],
|
|
20
20
|
"properties": {
|
|
21
|
+
"planSummary": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "One-line plain-language summary of the plan"
|
|
24
|
+
},
|
|
21
25
|
"reasoning": {
|
|
22
26
|
"type": "string",
|
|
23
27
|
"description": "Analysis of what needs to happen and why"
|