@gyoungwe/research-suite 0.1.3 → 0.1.5

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.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "version": 1,
3
3
  "generator": "packages/research-suite/scripts/build.mjs",
4
- "packageVersion": "0.1.3",
4
+ "packageVersion": "0.1.5",
5
5
  "bundled": [
6
6
  "@gyoungwe/pi-core",
7
7
  "@gyoungwe/pi-knowledge",
8
8
  "@gyoungwe/pi-research"
9
9
  ],
10
- "dependenciesSha256": "b9f96897420917b045d23eab8667a17145c637d2c9784359f8f049e872d1e782"
10
+ "dependenciesSha256": "ee57d5411edbbd02065e3d91ce5ac3d528c0faa77f81111aabd16c4062a1a6ca"
11
11
  }
@@ -4,9 +4,11 @@ Portable Pi extension for Drone's task ledger and user-facing core tools:
4
4
  `ask_user`, `set_status`, `todo`, `deliver_files`, and `memory_save`.
5
5
 
6
6
  It also exposes `/drone-doctor` (a stable JSON host/package diagnostic) and
7
- `/drone-example` (a read-only research example preview, with `--run` for an
8
- explicit user question). The example reports `needs-data`, `blocked`, `ready`,
9
- or `started`; it never claims a scientific result without source receipts.
7
+ `/drone-example` (a read-only example preview). The example accepts
8
+ `knowledge`, `research`, `analysis`, or `evidence` profiles, with `research`
9
+ as the default; add `--run <question>` only when an explicit read-only run is
10
+ wanted. Reports distinguish `unconfigured`, `needs-data`, `blocked`, `ready`,
11
+ and `started`, and never claim a scientific result without source receipts.
10
12
 
11
13
  The package also registers the `@drone/tasks` runtime. Native Pi uses the
12
14
  extension context's `ctx.ui`; Drone Desktop can inject its existing ask gate
@@ -3,6 +3,6 @@
3
3
  "generator": "scripts/build-pi-core.mjs",
4
4
  "inputsSha256": "de6fabddabb2c24748d325d3484d0c76bfde8ede915da8225d7f4d47927f282c",
5
5
  "outputs": {
6
- "dist/index.mjs": "df76a92939ab5d6f32c87d6795cafeabe54a90c2bc952c7efdffbfa806996f1b"
6
+ "dist/index.mjs": "6c3bdc2006cf6e329f10492c943a32fb50f1ddc8d32175fbcd99605df5fde1bb"
7
7
  }
8
8
  }
@@ -101,7 +101,8 @@ function createStandaloneRuntime(log = {}) {
101
101
  return runtime;
102
102
  }
103
103
  function currentRuntime() {
104
- if (contexts.getStore()) return contexts.getStore();
104
+ const scoped = contexts.getStore();
105
+ if (scoped) return scoped;
105
106
  if (installedRuntime) return installedRuntime;
106
107
  if (!standaloneRuntime) standaloneRuntime = createStandaloneRuntime();
107
108
  return standaloneRuntime;
@@ -144,10 +145,7 @@ function runtimeSlot(domain, slot, create) {
144
145
  }
145
146
  }
146
147
  );
147
- return (
148
- /** @type {T} */
149
- proxy
150
- );
148
+ return proxy;
151
149
  }
152
150
 
153
151
  // ../tasks/src/runtime-compiled/acceptance.mjs
@@ -2818,6 +2816,228 @@ Use task_status for operational delivery. Verify unknown outcomes before repeati
2818
2816
  return journal;
2819
2817
  }
2820
2818
 
2819
+ // src/drone-commands.ts
2820
+ import { readFileSync } from "node:fs";
2821
+ import { createRequire } from "node:module";
2822
+ import { join } from "node:path";
2823
+ var DRONE_COMMAND_SCHEMA_VERSION = 1;
2824
+ var PI_CORE_PACKAGE_VERSION = "0.1.3";
2825
+ var PI_HOST_RANGE = ">=1.1.0 <2.0.0";
2826
+ var CORE_TOOLS = [
2827
+ "ask_user",
2828
+ "set_status",
2829
+ "todo",
2830
+ "deliver_files",
2831
+ "memory_save",
2832
+ "task_plan",
2833
+ "task_status",
2834
+ "task_wait",
2835
+ "task_reconcile",
2836
+ "task_evidence_restore"
2837
+ ];
2838
+ var EXAMPLE_PROFILES = {
2839
+ knowledge: {
2840
+ title: "Knowledge Vault example",
2841
+ steps: ["check the local Vault", "search local knowledge", "cite the retrieved note paths"],
2842
+ requiredTools: ["knowledge_status", "knowledge_search"],
2843
+ missingToolsNext: "\u5B89\u88C5\u5E76\u542F\u7528 pi-knowledge \u540E\u91CD\u8BD5 /drone-example knowledge",
2844
+ missingDataNext: "\u63D0\u4F9B\u4E00\u4E2A\u77E5\u8BC6\u95EE\u9898\uFF1A/drone-example knowledge --run <\u95EE\u9898>"
2845
+ },
2846
+ research: {
2847
+ title: "Evidence-gated local research example",
2848
+ steps: ["inspect local knowledge", "read at least two sources", "answer with source receipts"],
2849
+ requiredTools: ["research_search_sources", "research_read_source", "research_answer_sources"],
2850
+ missingToolsNext: "\u5B89\u88C5\u5E76\u542F\u7528 pi-research \u540E\u91CD\u8BD5 /drone-example research",
2851
+ missingDataNext: "\u63D0\u4F9B\u4E00\u4E2A\u7814\u7A76\u95EE\u9898\uFF1A/drone-example research --run <\u7814\u7A76\u95EE\u9898>"
2852
+ },
2853
+ analysis: {
2854
+ title: "Analysis readiness example",
2855
+ requiresContainer: true,
2856
+ steps: [
2857
+ "list compatible analysis adapters",
2858
+ "assess input readiness",
2859
+ "report missing data before execution"
2860
+ ],
2861
+ requiredTools: ["analysis_list_adapters", "analysis_assess_readiness"],
2862
+ missingToolsNext: "\u5B89\u88C5\u5E76\u542F\u7528 pi-analysis \u540E\u91CD\u8BD5 /drone-example analysis",
2863
+ missingDataNext: "\u63D0\u4F9B\u8F93\u5165\u4E0E\u5206\u6790\u95EE\u9898\uFF1A/drone-example analysis --run <\u5206\u6790\u95EE\u9898>"
2864
+ },
2865
+ evidence: {
2866
+ title: "Evidence validation example",
2867
+ steps: ["validate an artifact manifest", "validate an evidence capsule", "verify replay metadata"],
2868
+ requiredTools: ["evidence_validate_manifest", "evidence_validate_capsule", "evidence_verify_replay"],
2869
+ missingToolsNext: "\u5B89\u88C5\u5E76\u542F\u7528 pi-evidence \u540E\u91CD\u8BD5 /drone-example evidence",
2870
+ missingDataNext: "\u63D0\u4F9B\u5F85\u6838\u9A8C\u7684\u8BC1\u636E\u5BF9\u8C61\uFF1A/drone-example evidence --run <\u5BF9\u8C61>"
2871
+ }
2872
+ };
2873
+ var EXAMPLE_KINDS = new Set(Object.keys(EXAMPLE_PROFILES));
2874
+ function packageVersion() {
2875
+ const configured = process.env.PI_VERSION?.trim();
2876
+ if (configured) return { version: configured, source: "PI_VERSION" };
2877
+ try {
2878
+ const require2 = createRequire(import.meta.url);
2879
+ for (const base of require2.resolve.paths("@earendil-works/pi-coding-agent") ?? []) {
2880
+ const packagePath = join(base, "@earendil-works/pi-coding-agent", "package.json");
2881
+ try {
2882
+ const metadata = JSON.parse(readFileSync(packagePath, "utf8"));
2883
+ if (typeof metadata.version === "string" && metadata.version.length > 0)
2884
+ return { version: metadata.version, source: "resolved-package" };
2885
+ } catch {
2886
+ }
2887
+ }
2888
+ } catch {
2889
+ }
2890
+ return { version: null, source: "unavailable" };
2891
+ }
2892
+ function snapshot(pi) {
2893
+ const tools = typeof pi?.getAllTools === "function" ? pi.getAllTools().map((tool) => String(tool?.name || "")).filter(Boolean) : typeof pi?.getActiveTools === "function" ? pi.getActiveTools().map((name) => String(name)).filter(Boolean) : [];
2894
+ const commands = typeof pi?.getCommands === "function" ? pi.getCommands().map((command) => String(command?.name || "")).filter(Boolean) : [];
2895
+ return { tools: [...new Set(tools)].sort(), commands: [...new Set(commands)].sort() };
2896
+ }
2897
+ function isSupportedPiHost(version) {
2898
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(version.trim());
2899
+ if (!match) return false;
2900
+ const major = Number(match[1]);
2901
+ const minor = Number(match[2]);
2902
+ const patch = Number(match[3]);
2903
+ return major === 1 && (minor > 1 || minor === 1 && patch >= 0);
2904
+ }
2905
+ function buildDoctorReport(pi, options = {}) {
2906
+ const current = snapshot(pi);
2907
+ const missingTools = CORE_TOOLS.filter((name) => !current.tools.includes(name));
2908
+ const missingCommands = ["drone-doctor", "drone-example"].filter(
2909
+ (name) => !current.commands.includes(name)
2910
+ );
2911
+ const resolved = options.hostVersion === void 0 ? packageVersion() : { version: options.hostVersion, source: "host-contract" };
2912
+ const hostCompatible = resolved.version ? isSupportedPiHost(resolved.version) : null;
2913
+ const hostKind = options.hostKind || "native-pi";
2914
+ const checks = [
2915
+ {
2916
+ id: "core-tools",
2917
+ status: missingTools.length ? "blocked" : "pass",
2918
+ detail: missingTools.length ? "pi-core tools are missing" : "all pi-core tools are registered",
2919
+ ...missingTools.length ? { missing: missingTools } : {}
2920
+ },
2921
+ {
2922
+ id: "drone-commands",
2923
+ status: missingCommands.length ? "blocked" : "pass",
2924
+ detail: missingCommands.length ? "Drone onboarding commands are missing" : "doctor and example commands are registered",
2925
+ ...missingCommands.length ? { missing: missingCommands } : {}
2926
+ },
2927
+ {
2928
+ id: "pi-host-version",
2929
+ status: resolved.version ? hostCompatible ? "pass" : "incompatible" : "unknown",
2930
+ detail: resolved.version ? hostCompatible ? `resolved Pi host ${resolved.version}` : `Pi host ${resolved.version} is outside ${PI_HOST_RANGE}` : "Pi host version is not exposed by this host"
2931
+ }
2932
+ ];
2933
+ const blocked = checks.some((check) => check.status === "blocked");
2934
+ const incompatible = checks.some((check) => check.status === "incompatible");
2935
+ return {
2936
+ schemaVersion: DRONE_COMMAND_SCHEMA_VERSION,
2937
+ command: "drone-doctor",
2938
+ status: blocked ? "blocked" : incompatible ? "incompatible" : resolved.version ? "pass" : "unknown",
2939
+ plugin: { name: "@gyoungwe/pi-core", version: PI_CORE_PACKAGE_VERSION, piRange: PI_HOST_RANGE },
2940
+ host: { kind: hostKind, version: resolved.version || null, source: resolved.source },
2941
+ checks,
2942
+ commands: current.commands,
2943
+ tools: current.tools,
2944
+ next: blocked ? "\u5B89\u88C5\u6216\u91CD\u65B0\u52A0\u8F7D\u7F3A\u5931\u7684 Drone \u63D2\u4EF6\u540E\u91CD\u8BD5 /drone-doctor" : incompatible ? `\u5347\u7EA7 Pi \u5230 ${PI_HOST_RANGE} \u540E\u91CD\u8BD5 /drone-doctor` : null
2945
+ };
2946
+ }
2947
+ function buildExampleReport(pi, mode = "preview", question, options = {}) {
2948
+ const example = options.example ?? "research";
2949
+ const profile = EXAMPLE_PROFILES[example];
2950
+ const current = snapshot(pi);
2951
+ const missingTools = profile.requiredTools.filter((name) => !current.tools.includes(name));
2952
+ const hasQuestion = Boolean(question?.trim());
2953
+ const knowledgeStatus = example === "knowledge" ? options.knowledgeStatus ?? (process.env.DRONE_KNOWLEDGE_DIR?.trim() ? "unknown" : "unconfigured") : void 0;
2954
+ const containerAvailable = options.containerAvailable ?? Boolean(process.env.DRONE_CONTAINER_RUNTIME?.trim());
2955
+ const missingContainer = Boolean(profile.requiresContainer && !containerAvailable);
2956
+ const status2 = missingTools.length ? "blocked" : knowledgeStatus === "unconfigured" ? "unconfigured" : knowledgeStatus === "unknown" ? "needs-data" : missingContainer ? "needs-container" : mode === "run" && hasQuestion ? "started" : hasQuestion ? "ready" : "needs-data";
2957
+ return {
2958
+ schemaVersion: DRONE_COMMAND_SCHEMA_VERSION,
2959
+ command: "drone-example",
2960
+ example,
2961
+ status: status2,
2962
+ mode,
2963
+ title: profile.title,
2964
+ steps: [...profile.steps],
2965
+ requiredTools: [...profile.requiredTools],
2966
+ missingTools: [...missingTools],
2967
+ next: missingTools.length ? profile.missingToolsNext : missingContainer ? "\u767B\u8BB0\u5E76\u542F\u7528\u4E00\u4E2A\u5BB9\u5668\u8FD0\u884C\u65F6\u540E\u91CD\u8BD5 /drone-example analysis" : knowledgeStatus === "unconfigured" ? "\u5148\u8FD0\u884C /drone-init \u7ED1\u5B9A\u672C\u5730 Vault\uFF0C\u518D\u91CD\u8BD5 /drone-example knowledge" : knowledgeStatus === "unknown" ? "\u65E0\u6CD5\u786E\u8BA4\u672C\u5730 Vault \u72B6\u6001\uFF1B\u5148\u8FD0\u884C /drone-init \u6216\u68C0\u67E5\u77E5\u8BC6\u5E93\u63D2\u4EF6\u540E\u91CD\u8BD5" : hasQuestion ? mode === "run" ? `${profile.title} \u5DF2\u6392\u961F\uFF1B\u7B49\u5F85\u771F\u5B9E\u56DE\u6267` : `\u8FD0\u884C /drone-example ${example} --run <\u95EE\u9898> \u5F00\u59CB\u53EA\u8BFB\u793A\u4F8B` : profile.missingDataNext,
2968
+ ...hasQuestion ? { question: question?.trim() } : {}
2969
+ };
2970
+ }
2971
+ function parseExampleArgs(args) {
2972
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
2973
+ let mode = "preview";
2974
+ const remaining = tokens.filter((token) => {
2975
+ if (token === "--run") {
2976
+ mode = "run";
2977
+ return false;
2978
+ }
2979
+ return true;
2980
+ });
2981
+ const candidate = remaining[0]?.toLowerCase();
2982
+ const example = candidate && EXAMPLE_KINDS.has(candidate) ? candidate : "research";
2983
+ if (candidate && EXAMPLE_KINDS.has(candidate)) remaining.shift();
2984
+ const question = remaining.join(" ").trim();
2985
+ return { mode, example, ...question ? { question } : {} };
2986
+ }
2987
+ async function resolveKnowledgeStatus(pi, ctx) {
2988
+ if (!process.env.DRONE_KNOWLEDGE_DIR?.trim()) return "unconfigured";
2989
+ const tool = typeof pi?.getAllTools === "function" ? pi.getAllTools().find((candidate) => candidate?.name === "knowledge_status") : void 0;
2990
+ if (typeof tool?.execute !== "function") return "unknown";
2991
+ try {
2992
+ const result = await tool.execute(
2993
+ "drone-example:knowledge-status",
2994
+ {},
2995
+ new AbortController().signal,
2996
+ () => void 0,
2997
+ ctx
2998
+ );
2999
+ const status2 = result?.details?.status ?? result?.status;
3000
+ if (status2 === "unconfigured") return "unconfigured";
3001
+ if (status2 === "configured") return "configured";
3002
+ } catch {
3003
+ }
3004
+ return "unknown";
3005
+ }
3006
+ function emitReport(report, ctx) {
3007
+ const message = JSON.stringify(report);
3008
+ if (ctx.mode === "print" || ctx.mode === "json") console.log(message);
3009
+ else
3010
+ ctx.ui.notify(
3011
+ message,
3012
+ report.status === "blocked" || report.status === "unconfigured" || report.status === "needs-container" || report.status === "incompatible" ? "warning" : "info"
3013
+ );
3014
+ }
3015
+ function registerDroneCommands(pi, options = {}) {
3016
+ pi.registerCommand("drone-doctor", {
3017
+ description: "Check the resolved Pi host, core tools and Drone command contract",
3018
+ handler: async (_args, ctx) => emitReport(buildDoctorReport(pi, options), ctx)
3019
+ });
3020
+ pi.registerCommand("drone-example", {
3021
+ description: "Preview or start a read-only Drone knowledge, research, analysis or evidence example",
3022
+ handler: async (args, ctx) => {
3023
+ const parsed = parseExampleArgs(args);
3024
+ const knowledgeStatus = parsed.example === "knowledge" ? await resolveKnowledgeStatus(pi, ctx) : void 0;
3025
+ const report = buildExampleReport(pi, parsed.mode, parsed.question, {
3026
+ example: parsed.example,
3027
+ knowledgeStatus
3028
+ });
3029
+ if (parsed.mode === "run" && report.status === "started" && typeof pi.sendUserMessage === "function") {
3030
+ await pi.sendUserMessage(
3031
+ `Run a read-only Drone ${report.example} example for this question: ${parsed.question}
3032
+ Use local evidence first, preserve source URIs and hashes, and report blocked/unknown states instead of guessing.`,
3033
+ { deliverAs: "followUp", expandPromptTemplates: true }
3034
+ );
3035
+ }
3036
+ emitReport(report, ctx);
3037
+ }
3038
+ });
3039
+ }
3040
+
2821
3041
  // ../shared/src/analysis-orchestration.ts
2822
3042
  var ANALYSIS_STAGES = Object.freeze([
2823
3043
  "intake",
@@ -16954,12 +17174,12 @@ import { stat as stat2 } from "node:fs/promises";
16954
17174
 
16955
17175
  // src/path.ts
16956
17176
  import { homedir as homedir2 } from "node:os";
16957
- import { isAbsolute as isAbsolute5, join, resolve as resolve6 } from "node:path";
17177
+ import { isAbsolute as isAbsolute5, join as join2, resolve as resolve6 } from "node:path";
16958
17178
  var UNICODE_SPACES = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF]/g;
16959
17179
  function resolveToolPath(rawPath, cwd, home = homedir2()) {
16960
17180
  let path = rawPath.replace(UNICODE_SPACES, " ");
16961
17181
  if (path === "~") path = home;
16962
- else if (path.startsWith("~/")) path = join(home, path.slice(2));
17182
+ else if (path.startsWith("~/")) path = join2(home, path.slice(2));
16963
17183
  return isAbsolute5(path) ? path : resolve6(cwd, path);
16964
17184
  }
16965
17185
 
@@ -17020,13 +17240,13 @@ function makeDeliverFilesTool() {
17020
17240
  }
17021
17241
 
17022
17242
  // src/memory.ts
17023
- import { mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
17024
- import { join as join2 } from "node:path";
17243
+ import { mkdirSync, readdirSync, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync } from "node:fs";
17244
+ import { join as join3 } from "node:path";
17025
17245
  var MEMORY_TYPES = ["user", "feedback", "project", "reference"];
17026
17246
  var MEMORY_INDEX = "MEMORY.md";
17027
17247
  var MAX_INDEX_LINES = 200;
17028
17248
  function memoryDir(cwd) {
17029
- return join2(cwd, ".pi", "memory");
17249
+ return join3(cwd, ".pi", "memory");
17030
17250
  }
17031
17251
  function memorySlug(name) {
17032
17252
  const slug = name.trim().toLowerCase().replace(/[^\p{L}\p{N}]+/gu, "-").replace(/^-+|-+$/g, "").slice(0, 64);
@@ -17079,7 +17299,7 @@ function listMemories(cwd) {
17079
17299
  }
17080
17300
  const out = [];
17081
17301
  for (const file of files) {
17082
- const entry = parseMemory(readFileSync(join2(dir, file), "utf8"));
17302
+ const entry = parseMemory(readFileSync2(join3(dir, file), "utf8"));
17083
17303
  if (entry) out.push({ ...entry, file });
17084
17304
  }
17085
17305
  return out;
@@ -17088,14 +17308,14 @@ function writeMemory(cwd, entry) {
17088
17308
  const dir = memoryDir(cwd);
17089
17309
  mkdirSync(dir, { recursive: true });
17090
17310
  const file = `${entry.type}_${memorySlug(entry.name)}.md`;
17091
- atomicWrite(join2(dir, file), serializeMemory(entry));
17092
- atomicWrite(join2(dir, MEMORY_INDEX), renderMemoryIndex(listMemories(cwd)));
17311
+ atomicWrite(join3(dir, file), serializeMemory(entry));
17312
+ atomicWrite(join3(dir, MEMORY_INDEX), renderMemoryIndex(listMemories(cwd)));
17093
17313
  return file;
17094
17314
  }
17095
17315
  function memoryIndexPrompt(cwd) {
17096
17316
  let index;
17097
17317
  try {
17098
- index = readFileSync(join2(memoryDir(cwd), MEMORY_INDEX), "utf8");
17318
+ index = readFileSync2(join3(memoryDir(cwd), MEMORY_INDEX), "utf8");
17099
17319
  } catch {
17100
17320
  return [];
17101
17321
  }
@@ -17111,8 +17331,8 @@ ${shown.join("\n")}${lines.length > shown.length ? `
17111
17331
  function forgetMemory(cwd, file) {
17112
17332
  if (!/^[^\\/]+\.md$/.test(file) || file === MEMORY_INDEX) return false;
17113
17333
  if (!listMemories(cwd).some((e) => e.file === file)) return false;
17114
- rmSync(join2(memoryDir(cwd), file));
17115
- atomicWrite(join2(memoryDir(cwd), MEMORY_INDEX), renderMemoryIndex(listMemories(cwd)));
17334
+ rmSync(join3(memoryDir(cwd), file));
17335
+ atomicWrite(join3(memoryDir(cwd), MEMORY_INDEX), renderMemoryIndex(listMemories(cwd)));
17116
17336
  return true;
17117
17337
  }
17118
17338
 
@@ -17309,136 +17529,6 @@ ${formatTodoList(todos)}`;
17309
17529
  };
17310
17530
  }
17311
17531
 
17312
- // src/drone-commands.ts
17313
- import { readFileSync as readFileSync2 } from "node:fs";
17314
- import { createRequire } from "node:module";
17315
- import { dirname, join as join3 } from "node:path";
17316
- var DRONE_COMMAND_SCHEMA_VERSION = 1;
17317
- var PI_CORE_PACKAGE_VERSION = "0.1.1";
17318
- var PI_HOST_RANGE = ">=1.1.0 <2.0.0";
17319
- var CORE_TOOLS = [
17320
- "ask_user",
17321
- "set_status",
17322
- "todo",
17323
- "deliver_files",
17324
- "memory_save",
17325
- "task_plan",
17326
- "task_status",
17327
- "task_wait",
17328
- "task_reconcile",
17329
- "task_evidence_restore"
17330
- ];
17331
- var EXAMPLE_TOOLS = [
17332
- "knowledge_status",
17333
- "knowledge_search",
17334
- "research_search_sources",
17335
- "research_read_source",
17336
- "research_answer_sources"
17337
- ];
17338
- function packageVersion() {
17339
- const configured = process.env.PI_VERSION?.trim();
17340
- if (configured) return { version: configured, source: "PI_VERSION" };
17341
- try {
17342
- const require2 = createRequire(import.meta.url);
17343
- const entry = require2.resolve("@earendil-works/pi-coding-agent");
17344
- const packagePath = join3(dirname(entry), "..", "package.json");
17345
- const metadata = JSON.parse(readFileSync2(packagePath, "utf8"));
17346
- if (typeof metadata.version === "string" && metadata.version.length > 0)
17347
- return { version: metadata.version, source: "resolved-package" };
17348
- } catch {
17349
- }
17350
- return { version: null, source: "unavailable" };
17351
- }
17352
- function snapshot(pi) {
17353
- const tools = typeof pi?.getAllTools === "function" ? pi.getAllTools().map((tool) => String(tool?.name || "")).filter(Boolean) : typeof pi?.getActiveTools === "function" ? pi.getActiveTools().map((name) => String(name)).filter(Boolean) : [];
17354
- const commands = typeof pi?.getCommands === "function" ? pi.getCommands().map((command) => String(command?.name || "")).filter(Boolean) : [];
17355
- return { tools: [...new Set(tools)].sort(), commands: [...new Set(commands)].sort() };
17356
- }
17357
- function buildDoctorReport(pi, options = {}) {
17358
- const current = snapshot(pi);
17359
- const missingTools = CORE_TOOLS.filter((name) => !current.tools.includes(name));
17360
- const missingCommands = ["drone-doctor", "drone-example"].filter((name) => !current.commands.includes(name));
17361
- const resolved = options.hostVersion === void 0 ? packageVersion() : { version: options.hostVersion, source: "host-contract" };
17362
- const hostKind = options.hostKind || "native-pi";
17363
- const checks = [
17364
- {
17365
- id: "core-tools",
17366
- status: missingTools.length ? "blocked" : "pass",
17367
- detail: missingTools.length ? "pi-core tools are missing" : "all pi-core tools are registered",
17368
- ...missingTools.length ? { missing: missingTools } : {}
17369
- },
17370
- {
17371
- id: "drone-commands",
17372
- status: missingCommands.length ? "blocked" : "pass",
17373
- detail: missingCommands.length ? "Drone onboarding commands are missing" : "doctor and example commands are registered",
17374
- ...missingCommands.length ? { missing: missingCommands } : {}
17375
- },
17376
- {
17377
- id: "pi-host-version",
17378
- status: resolved.version ? "pass" : "unknown",
17379
- detail: resolved.version ? `resolved Pi host ${resolved.version}` : "Pi host version is not exposed by this host"
17380
- }
17381
- ];
17382
- const blocked = checks.some((check) => check.status === "blocked");
17383
- return {
17384
- schemaVersion: DRONE_COMMAND_SCHEMA_VERSION,
17385
- command: "drone-doctor",
17386
- status: blocked ? "blocked" : resolved.version ? "pass" : "unknown",
17387
- plugin: { name: "@gyoungwe/pi-core", version: PI_CORE_PACKAGE_VERSION, piRange: PI_HOST_RANGE },
17388
- host: { kind: hostKind, version: resolved.version || null, source: resolved.source },
17389
- checks,
17390
- commands: current.commands,
17391
- tools: current.tools,
17392
- next: blocked ? "\u5B89\u88C5\u6216\u91CD\u65B0\u52A0\u8F7D\u7F3A\u5931\u7684 Drone \u63D2\u4EF6\u540E\u91CD\u8BD5 /drone-doctor" : null
17393
- };
17394
- }
17395
- function buildExampleReport(pi, mode = "preview", question) {
17396
- const current = snapshot(pi);
17397
- const missingTools = EXAMPLE_TOOLS.filter((name) => !current.tools.includes(name));
17398
- const hasQuestion = Boolean(question?.trim());
17399
- const status2 = missingTools.length ? "blocked" : mode === "run" && hasQuestion ? "started" : hasQuestion ? "ready" : "needs-data";
17400
- return {
17401
- schemaVersion: DRONE_COMMAND_SCHEMA_VERSION,
17402
- command: "drone-example",
17403
- status: status2,
17404
- mode,
17405
- title: "Evidence-gated local research example",
17406
- steps: ["inspect local knowledge", "read at least two sources", "answer with source receipts"],
17407
- requiredTools: [...EXAMPLE_TOOLS],
17408
- missingTools: [...missingTools],
17409
- next: missingTools.length ? "\u5B89\u88C5\u5E76\u542F\u7528 pi-knowledge \u4E0E pi-research \u540E\u91CD\u8BD5 /drone-example" : hasQuestion ? mode === "run" ? "\u7814\u7A76\u56DE\u5408\u5DF2\u6392\u961F\uFF1B\u7B49\u5F85\u771F\u5B9E\u6765\u6E90\u56DE\u6267" : "\u8FD0\u884C /drone-example --run <\u7814\u7A76\u95EE\u9898> \u5F00\u59CB\u53EA\u8BFB\u793A\u4F8B" : "\u63D0\u4F9B\u4E00\u4E2A\u7814\u7A76\u95EE\u9898\uFF1A/drone-example --run <\u7814\u7A76\u95EE\u9898>",
17410
- ...hasQuestion ? { question: question?.trim() } : {}
17411
- };
17412
- }
17413
- function emitReport(report, ctx) {
17414
- const message = JSON.stringify(report);
17415
- if (ctx.mode === "print" || ctx.mode === "json") console.log(message);
17416
- else ctx.ui.notify(message, report.status === "blocked" ? "warning" : "info");
17417
- }
17418
- function registerDroneCommands(pi, options = {}) {
17419
- pi.registerCommand("drone-doctor", {
17420
- description: "Check the resolved Pi host, core tools and Drone command contract",
17421
- handler: async (_args, ctx) => emitReport(buildDoctorReport(pi, options), ctx)
17422
- });
17423
- pi.registerCommand("drone-example", {
17424
- description: "Preview or start a read-only evidence-gated research example",
17425
- handler: async (args, ctx) => {
17426
- const trimmed = args.trim();
17427
- const run = trimmed.startsWith("--run");
17428
- const question = run ? trimmed.slice("--run".length).trim() : trimmed;
17429
- const report = buildExampleReport(pi, run ? "run" : "preview", question || void 0);
17430
- if (run && report.status === "started" && typeof pi.sendUserMessage === "function") {
17431
- await pi.sendUserMessage(
17432
- `Run a read-only Drone research example for this question: ${question}
17433
- Use local evidence first, read at least two sources, preserve source URIs and hashes, and report blocked/unknown states instead of guessing.`,
17434
- { deliverAs: "followUp", expandPromptTemplates: true }
17435
- );
17436
- }
17437
- emitReport(report, ctx);
17438
- }
17439
- });
17440
- }
17441
-
17442
17532
  // src/index.ts
17443
17533
  var DEFAULT_HOST_VERSION = "1.1.0";
17444
17534
  function createNativePiHostPort(ctx, hostVersion = DEFAULT_HOST_VERSION) {
@@ -17511,7 +17601,9 @@ function registerPiCore(pi, options = {}) {
17511
17601
  activeContext = void 0;
17512
17602
  });
17513
17603
  registerTaskRuntime(pi);
17514
- registerDroneCommands(pi, { hostKind: options.host?.host === "drone-desktop" ? "drone-desktop" : "native-pi" });
17604
+ registerDroneCommands(pi, {
17605
+ hostKind: options.host?.host === "drone-desktop" ? "drone-desktop" : "native-pi"
17606
+ });
17515
17607
  const ask = options.ask || ((request, signal, context) => askWithNativeUi(request, signal, context || activeContext));
17516
17608
  pi.registerTool(makeAskUserTool({ ask }));
17517
17609
  pi.registerTool(makeStatusTool());
@@ -17543,6 +17635,7 @@ export {
17543
17635
  makeTodoTool,
17544
17636
  memoryIndexPrompt,
17545
17637
  normalizeTodos,
17638
+ parseExampleArgs,
17546
17639
  registerDroneCommands,
17547
17640
  registerPiCore,
17548
17641
  writeMemory
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gyoungwe/pi-core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Portable task, authorization, status, delivery and memory tools for native Pi",
5
5
  "keywords": [
6
6
  "pi-package"
package/package.json CHANGED
@@ -1,46 +1,60 @@
1
1
  {
2
- "name": "@gyoungwe/research-suite",
3
- "version": "0.1.3",
4
- "description": "Bundled Drone native Pi research suite",
5
- "keywords": ["pi-package", "research", "evidence"],
6
- "license": "MIT",
7
- "publishConfig": {"access": "public"},
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/Gyoungwe/drone-plugins.git",
11
- "directory": "packages/research-suite"
12
- },
13
- "type": "module",
14
- "files": ["package.json", "plugin.manifest.json", "README.md", "build-manifest.json", "prompts"],
15
- "scripts": {
16
- "build": "node scripts/build.mjs",
17
- "build:check": "node scripts/build.mjs --check",
18
- "typecheck": "node -e \"process.exit(0)\""
19
- },
20
- "pi": {
21
- "extensions": [
22
- "./node_modules/@gyoungwe/pi-core/dist/index.mjs",
23
- "./node_modules/@gyoungwe/pi-knowledge/dist/index.mjs",
24
- "./node_modules/@gyoungwe/pi-research/dist/index.mjs"
25
- ],
26
- "skills": [
27
- "./node_modules/@gyoungwe/pi-core/skills/*",
28
- "./node_modules/@gyoungwe/pi-knowledge/skills/*",
29
- "./node_modules/@gyoungwe/pi-research/skills/*"
30
- ],
31
- "prompts": ["./prompts/*.md"]
32
- },
33
- "dependencies": {
34
- "@gyoungwe/pi-core": "0.1.1",
35
- "@gyoungwe/pi-knowledge": "0.1.1",
36
- "@gyoungwe/pi-research": "0.1.0"
37
- },
38
- "bundleDependencies": [
39
- "@gyoungwe/pi-core",
40
- "@gyoungwe/pi-knowledge",
41
- "@gyoungwe/pi-research"
42
- ],
43
- "peerDependencies": {
44
- "@earendil-works/pi-coding-agent": ">=1.1.0 <2.0.0"
45
- }
2
+ "name": "@gyoungwe/research-suite",
3
+ "version": "0.1.5",
4
+ "description": "Bundled Drone native Pi research suite",
5
+ "keywords": [
6
+ "pi-package",
7
+ "research",
8
+ "evidence"
9
+ ],
10
+ "license": "MIT",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/Gyoungwe/drone-plugins.git",
17
+ "directory": "packages/research-suite"
18
+ },
19
+ "type": "module",
20
+ "files": [
21
+ "package.json",
22
+ "plugin.manifest.json",
23
+ "README.md",
24
+ "build-manifest.json",
25
+ "prompts"
26
+ ],
27
+ "scripts": {
28
+ "build": "node scripts/build.mjs",
29
+ "build:check": "node scripts/build.mjs --check",
30
+ "typecheck": "node -e \"process.exit(0)\""
31
+ },
32
+ "pi": {
33
+ "extensions": [
34
+ "./node_modules/@gyoungwe/pi-core/dist/index.mjs",
35
+ "./node_modules/@gyoungwe/pi-knowledge/dist/index.mjs",
36
+ "./node_modules/@gyoungwe/pi-research/dist/index.mjs"
37
+ ],
38
+ "skills": [
39
+ "./node_modules/@gyoungwe/pi-core/skills/*",
40
+ "./node_modules/@gyoungwe/pi-knowledge/skills/*",
41
+ "./node_modules/@gyoungwe/pi-research/skills/*"
42
+ ],
43
+ "prompts": [
44
+ "./prompts/*.md"
45
+ ]
46
+ },
47
+ "dependencies": {
48
+ "@gyoungwe/pi-core": "0.1.3",
49
+ "@gyoungwe/pi-knowledge": "0.1.1",
50
+ "@gyoungwe/pi-research": "0.1.0"
51
+ },
52
+ "bundleDependencies": [
53
+ "@gyoungwe/pi-core",
54
+ "@gyoungwe/pi-knowledge",
55
+ "@gyoungwe/pi-research"
56
+ ],
57
+ "peerDependencies": {
58
+ "@earendil-works/pi-coding-agent": ">=1.1.0 <2.0.0"
59
+ }
46
60
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "drone-research-suite",
4
- "version": "0.1.3",
4
+ "version": "0.1.5",
5
5
  "pi": {
6
6
  "apiVersion": 1,
7
7
  "minHostVersion": "1.1.0",