dsh-plugin-jules 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # dsh-plugin-jules
2
2
 
3
3
  [![CI](https://github.com/rbviz/dsh-plugin-jules/actions/workflows/ci.yml/badge.svg)](https://github.com/rbviz/dsh-plugin-jules/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/dsh-plugin-jules.svg)](https://www.npmjs.com/package/dsh-plugin-jules)
4
5
 
5
6
  Google [Jules](https://jules.google.com) as a [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) capability.
6
7
 
@@ -33,22 +34,49 @@ It talks to the documented Jules v1alpha REST API directly and has **no runtime
33
34
 
34
35
  ## Install
35
36
 
36
- The package declares `dsh.bundle`, so it installs as an ordinary profile bundle. From a checkout of
37
- this repository:
37
+ The package declares `dsh.bundle`, so it installs as an ordinary profile bundle. `dsh plugin`
38
+ forwards its arguments to pnpm in the profile directory, so `add`, `update`, and `remove` are the
39
+ ordinary verbs. If the profile does not exist yet, the first command creates it.
38
40
 
39
- ```sh
40
- node scripts/link-dsh-deps.mjs # once, and after changing peerDependencies
41
- npm run build # compiles src/ to lib/
41
+ ### From npm
42
42
 
43
- dsh plugin --profile <your-profile> add /path/to/jules-plugin
43
+ ```sh
44
+ dsh plugin --profile <your-profile> add dsh-plugin-jules
44
45
  ```
45
46
 
46
- Then restart the harness. Confirm the layer composed:
47
+ Nothing compiles on your machine: `lib/` ships prebuilt, so there is no `prepare` script and no
48
+ `allowBuilds` permission to grant. The `@deepseek-ai/*` peer dependencies come from the harness
49
+ installation's own module fallback, so there is nothing else to install — this plugin adds no
50
+ runtime dependencies of its own.
51
+
52
+ **Restart the harness.** A running process keeps the bundle set it started with; an `add`, `update`,
53
+ or `remove` is picked up at the next start. Then confirm the layer composed:
47
54
 
48
55
  ```sh
49
56
  dsh --profile <your-profile> --dump-config | grep -A 3 'id: jules'
50
57
  ```
51
58
 
59
+ Upgrading and removing are the same passthrough, each followed by the same restart:
60
+
61
+ ```sh
62
+ dsh plugin --profile <your-profile> update dsh-plugin-jules
63
+ dsh plugin --profile <your-profile> remove dsh-plugin-jules
64
+ ```
65
+
66
+ ### From a checkout
67
+
68
+ To run your own build of the sources:
69
+
70
+ ```sh
71
+ node scripts/link-dsh-deps.mjs # once, and after changing peerDependencies
72
+ npm run build # compiles src/ to lib/
73
+
74
+ dsh plugin --profile <your-profile> add /path/to/jules-plugin
75
+ ```
76
+
77
+ The path spec is anchored to the directory you invoke from, so `add .` works from the checkout root.
78
+ Restart, then confirm as above.
79
+
52
80
  ### From GitHub
53
81
 
54
82
  ```sh
package/lib/index.d.ts CHANGED
@@ -97,8 +97,23 @@ export interface Config {
97
97
  }
98
98
  /** Schemastery configuration for loader defaults and the generated config catalog. */
99
99
  export declare const Config: z<Config>;
100
- /** Model guidance placed beside the subagent instructions. */
101
- export declare const JULES_PROMPT: string;
100
+ /**
101
+ * Model guidance for the Jules tool family.
102
+ *
103
+ * Written as an instruction and scoped to policy, like every in-box tool
104
+ * section: what each tool does is the tool description's job, so this says when
105
+ * to reach for the family and what not to do with it. The earlier draft opened
106
+ * by describing Jules instead, and spent most of its length restating the tool
107
+ * descriptions.
108
+ *
109
+ * The waiting half is conditional because `enableWatch: false` removes
110
+ * `jules_watch` from the composition entirely, and guidance naming a tool the
111
+ * model cannot call is worse than guidance that says less. `tool:web_search`
112
+ * sets the same precedent for its optional `web_fetch` companion.
113
+ * @param watchAvailable - whether `jules_watch` is registered in this scope.
114
+ * @returns the section text.
115
+ */
116
+ export declare function julesGuidance(watchAvailable: boolean): string;
102
117
  /**
103
118
  * Register the Jules tool family and its model guidance.
104
119
  * @param ctx - plugin context supplying the tool registry and credential seam.
package/lib/index.js CHANGED
@@ -80,22 +80,39 @@ export const Config = z.object({
80
80
  retryBaseDelayMs: z.number().step(1).min(1).default(DEFAULT_RETRY_BASE_DELAY_MS),
81
81
  retryMaxDelayMs: z.number().step(1).min(1).default(DEFAULT_RETRY_MAX_DELAY_MS),
82
82
  });
83
- /** Model guidance placed beside the subagent instructions. */
84
- export const JULES_PROMPT = 'Jules is a remote coding agent reachable through the jules_* tools. It runs asynchronously in the cloud on its own clone of a '
85
- + 'repository, so a session keeps working after your turn ends. '
86
- + 'DO NOT POLL. jules_create starts a session and returns its id; jules_watch registers a background watch and returns a job id; '
87
- + 'then END YOUR TURN and get on with something else. The watch notice wakes you when the session finishes, fails, needs a plan '
88
- + 'decision, or posts a message, and job_output reads what happened. Nothing needs checking in between waiting is the watcher\'s '
89
- + 'job, not yours, and a status call that returns what you already saw has cost a turn and bought nothing. '
90
- + 'jules_wait is the same wait held open in the foreground; use it only when you genuinely have nothing else to do. '
91
- + 'jules_status is for confirming an action you just took, following up a notice, or answering the user when they ask about a '
92
- + 'session never for waiting. '
93
- + 'The rest: jules_sources lists the repositories Jules may work in; jules_activities reads the event log, for diagnosing a stall '
94
- + 'rather than polling; jules_approve_plan releases a plan you have reviewed; jules_send_message answers or corrects the agent; '
95
- + 'jules_patch returns the unified diff, in slices when it is large. '
96
- + 'Ask for requirePlanApproval when a task will change existing code, then review the plan before approving it. '
97
- + 'Prefer finishing small work here; delegate a task that is long, independent, or better done in a clean checkout, and do not '
98
- + 'open several sessions for one task because the service throttles concurrent creation.';
83
+ /**
84
+ * Model guidance for the Jules tool family.
85
+ *
86
+ * Written as an instruction and scoped to policy, like every in-box tool
87
+ * section: what each tool does is the tool description's job, so this says when
88
+ * to reach for the family and what not to do with it. The earlier draft opened
89
+ * by describing Jules instead, and spent most of its length restating the tool
90
+ * descriptions.
91
+ *
92
+ * The waiting half is conditional because `enableWatch: false` removes
93
+ * `jules_watch` from the composition entirely, and guidance naming a tool the
94
+ * model cannot call is worse than guidance that says less. `tool:web_search`
95
+ * sets the same precedent for its optional `web_fetch` companion.
96
+ * @param watchAvailable - whether `jules_watch` is registered in this scope.
97
+ * @returns the section text.
98
+ */
99
+ export function julesGuidance(watchAvailable) {
100
+ const waiting = watchAvailable
101
+ ? 'jules_watch registers a background watch and returns a job id; then END YOUR TURN, and the harness wakes you with a notice when '
102
+ + 'the session finishes, fails, needs a plan decision, or posts a message. DO NOT POLL: a status call that returns what you '
103
+ + 'already saw has cost a turn and bought nothing. jules_wait holds that same wait open in the foreground, so reach for it only '
104
+ + 'when nothing else can proceed meanwhile.'
105
+ : 'jules_wait holds the turn open until the session finishes, fails, needs a plan decision, or posts a message. DO NOT POLL: a '
106
+ + 'status call that returns what you already saw has cost a turn and bought nothing.';
107
+ return 'Use the jules_* tools to delegate a coding task to Jules, a remote agent that works asynchronously in the cloud on its own '
108
+ + 'clone of a repository, so the session keeps working after your turn ends. jules_create returns a session id immediately. '
109
+ + waiting + ' '
110
+ + 'jules_status is for confirming an action you just took, following up a watch notice, or answering the user about a session — '
111
+ + 'never for waiting. '
112
+ + 'Ask for requirePlanApproval when a task will change existing code, then read the plan before jules_approve_plan releases it. '
113
+ + 'Prefer finishing small work here; delegate a task that is long, independent, or better done in a clean checkout, and do not '
114
+ + 'open several sessions for one task because the service throttles concurrent creation.';
115
+ }
99
116
  /**
100
117
  * Complete every optional field and reject combinations the schema cannot express.
101
118
  * @param config - the validated configuration section.
@@ -225,10 +242,23 @@ export function apply(ctx, config) {
225
242
  // positions owned by particular tool families, and Jules is the same kind of
226
243
  // thing a subagent is — a delegation target — so its guidance belongs beside
227
244
  // those instructions rather than in an unrelated slot. Equal orders fall back
228
- // to name order, which is stable.
245
+ // to name order, which is stable. The system-prompt README documents the
246
+ // alternative for out-of-tree packages — "external contributions may use any
247
+ // finite order" — but a borrowed allocated position cannot collide with a
248
+ // future in-box slot, while a hand-picked number can.
229
249
  order: ctx.systemPrompt.getSectionOrder('TOOL_SUBAGENT'),
230
250
  // Evaluated per assembly, so the orphan note appears the moment the plugin
231
251
  // loads after a restart and disappears as watches are re-armed.
232
- text: () => JULES_PROMPT + orphanNote((journal?.pending() ?? []).filter(record => !live.has(record.session))),
252
+ //
253
+ // Empty text is dropped before rendering, so an agent whose scope excludes
254
+ // the family is never told about tools it cannot call — the same gate
255
+ // `tool:read` and `tool:subagent` apply. `jules_create` stands in for the
256
+ // family: it registers unconditionally and is the entry point this guidance
257
+ // is about. Gating ahead of the note also stops an agent without Jules tools
258
+ // from being handed a list of watches to re-arm.
259
+ text: ({ scope }) => ctx.tools.get('jules_create', scope) === undefined
260
+ ? ''
261
+ : julesGuidance(ctx.tools.get('jules_watch', scope) !== undefined)
262
+ + orphanNote((journal?.pending() ?? []).filter(record => !live.has(record.session))),
233
263
  });
234
264
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-jules",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Google Jules remote coding agent integration for DeepSeek Harness",
5
5
  "keywords": [
6
6
  "dsh",