dsh-plugin-github-issues 0.8.1 → 0.8.3

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
@@ -18,6 +18,8 @@ worked in several Sessions.
18
18
 
19
19
  ![The pending issue card inside the composer](assets/pending.png)
20
20
 
21
+ ![The issue card in a sent message](assets/message-card.png)
22
+
21
23
  It is **read-only**: the plugin never writes to GitHub.
22
24
 
23
25
  ## Install
@@ -65,7 +67,8 @@ tarball (`dsh-plugin-github-issues.tgz`), installable by path.
65
67
  |---|---|---|
66
68
  | GitHub panel | left rail icon → main panel | organization → repository → **milestone** → assignee → state cascade (remembered across restarts) in one fixed toolbar; a default organization/repository is selected for you, the milestone dropdown lists only that repository's milestones, and only the list scrolls (search stays above it, the detail pane scrolls independently with the **full issue body rendered as sanitized GitHub-flavored Markdown**, milestone progress, labels, priority, assignees, linked/mentioned PRs and checks) |
67
69
  | Issues right column | right sidebar tab | the same filtered issue list beside the Conversation, for drag-and-drop handoff |
68
- | Composer card | inside the input box, above the editor | the staged issue as a draft-attachment-style card (240×64, GitHub glyph, `owner/repo#number`, state + title, hover-only remove). The card is not editable; it keeps its own space above the editor, survives a Workspace switch together with the draft, and is converted into the issue prompt on send |
70
+ | Composer card | inside the input box, above the editor | the staged issue as a draft-attachment-style card (240×64, GitHub glyph, `owner/repo#number`, state + title, hover-only remove). The card is not editable; it keeps its own space above the editor, survives a Workspace switch together with the draft, opens the issue URL when clicked, and is converted into the issue prompt on send |
71
+ | Sent issue card | in a sent user message | the prompt's `处理 GitHub Issue:owner/repo#number title` heading is rendered as the same clickable 240×64 issue card (state + title), and the metadata stays a Markdown table |
69
72
  | Linked chip | composer dock under the input | the Session's linked issue: state dot (green open / red closed) + `owner/repo#number`; the dot refreshes from GitHub on panel refresh, every poll, window focus and whenever the issue appears in the list; click for a detail popover, remove to unlink |
70
73
  | Handoff actions | issue detail | one-click **enter Session** (latest link), **new Session for this issue**, plus a linked-Session list with per-Session enter/unlink |
71
74
  | GitHub settings | Settings → GitHub | `gh` auth status and scopes, handoff behavior, prompt template |
@@ -123,6 +126,10 @@ Settings → GitHub → Prompt template. Variables: `{{repo}}`, `{{number}}`, `{
123
126
  - The default handoff prompt renders its issue metadata as a Markdown table, so it survives as a real
124
127
  table in the transcript after sending. Legacy pre-table prompts are upgraded once on load; **Reset
125
128
  to default** in Settings restores this template.
129
+ - The card marker is a single hair space (Unicode whitespace): `/command` or an `@reference` typed
130
+ after the card is preceded by whitespace, so the input trigger pipeline (and the command's leading
131
+ guard) works. Because it is whitespace, it also cannot accumulate into visible indentation while
132
+ typing. Both the composer card and the sent-message card open the issue URL.
126
133
  - Milestone choices come from the selected repository's full milestone list (open and closed).
127
134
  - Priority falls back organization Issue Field → `P0`–`P4` labels when no project field is present.
128
135
  - The list polls every 60–120 s while visible; use **Refresh** for an immediate update.
Binary file
package/docs/README.zh.md CHANGED
@@ -15,6 +15,8 @@ Issue 可以关联多个 Session。
15
15
 
16
16
  ![输入框里的待发送 Issue 卡片](../assets/pending.png)
17
17
 
18
+ ![发送后消息里的 Issue 卡片](../assets/message-card.png)
19
+
18
20
  插件对 GitHub **只读**,不会写入任何内容。
19
21
 
20
22
  ## 安装
@@ -107,6 +109,9 @@ dsh plugin --profile <name> add /path/to/dsh-plugin-github-issues
107
109
  - 详情展示完整正文(不是摘要、也不再限制在固定高度的小框里),按 Markdown 渲染并过滤危险 HTML。
108
110
  - 默认交接提示词把 Issue 元信息排成 Markdown 表格,发送后在对话里会渲染成真正的表格;旧版没有表格的
109
111
  提示词会在加载时自动升级一次,也可以在设置里点「恢复默认」重新套用。
112
+ - 卡片标记是一个 hair space(Unicode 空白字符):卡片后面输入 `/命令` 或 `@引用` 时前面天然有空白,
113
+ 输入触发管线和命令的 leading guard 都能工作;因为它本身是空白,也不会在打字时累积成可见缩进。
114
+ 输入框卡片和发送后的消息卡片都会打开 Issue 网址。
110
115
  - 里程碑的可选项来自当前仓库的完整里程碑列表(含已关闭)。
111
116
  - 优先级回退顺序:组织 Issue Field → `P0`–`P4` 标签(不再读取 Projects v2 项目字段)。
112
117
  - 列表可见时每 60–120 秒轮询一次;需要立刻更新点「刷新」。
package/lib/client.js CHANGED
@@ -106,9 +106,9 @@ function renderPrompt(issue, template) {
106
106
  \u2026\uFF08\u5DF2\u622A\u65AD\uFF09`;
107
107
  return text2;
108
108
  }
109
- var PENDING_DRAFT_SENTINEL = "\u2063\u200B";
109
+ var PENDING_DRAFT_SENTINEL = "\u200A";
110
110
  function composeHandoffPrompt(prompt, memo) {
111
- const extra = memo.split(PENDING_DRAFT_SENTINEL).join("").replace(/[\u200b\u200c\u200d\u2060\ufeff]/g, "").replace(/^\n+/, "").trim();
111
+ const extra = memo.split(PENDING_DRAFT_SENTINEL).join("").replace(/[\u200b\u200c\u200d\u2060\u2063\ufeff]/g, "").replace(/^\n+/, "").trim();
112
112
  return extra === "" ? prompt : `${prompt}
113
113
 
114
114
  ${extra}`;
@@ -797,9 +797,10 @@ function GitHubDropZone({ dragging, t, onDrop, onCancel }) {
797
797
  var import_jsx_runtime5 = require("react/jsx-runtime");
798
798
  var PENDING_CSS = `
799
799
  .ghp3-rail{position:absolute;top:8px;left:10px;right:10px;z-index:2;display:flex;align-items:flex-start;pointer-events:none}
800
- .ghp3-card{pointer-events:auto;position:relative;display:inline-flex;align-items:center;gap:10px;box-sizing:border-box;width:240px;max-width:100%;height:64px;padding:0 12px;border:0.5px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:var(--dsw-radius-lg,12px);background:var(--dsw-specific-input-major,var(--dsw-alias-bg-base));color:var(--dsw-alias-label-primary);text-align:left;font-family:inherit;cursor:pointer}
800
+ .ghp3-card{pointer-events:auto;position:relative;display:inline-flex;align-items:center;box-sizing:border-box;width:240px;max-width:100%;height:64px;border:0.5px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:var(--dsw-radius-lg,12px);background:var(--dsw-specific-input-major,var(--dsw-alias-bg-base));color:var(--dsw-alias-label-primary);text-align:left;font-family:inherit}
801
801
  .ghp3-card:hover{border-color:var(--dsw-alias-border-l3,rgba(0,0,0,.18))}
802
- .ghp3-card:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
802
+ .ghp3-card:focus-within{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
803
+ .ghp3-link{display:inline-flex;align-items:center;gap:10px;box-sizing:border-box;width:100%;height:100%;padding:0 12px;color:inherit;text-decoration:none;border-radius:inherit}
803
804
  .ghp3-icon{flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--dsw-radius-md,8px);background:color-mix(in srgb,var(--dsw-alias-state-business-primary,#4d6bfe) 12%,transparent);color:var(--dsw-alias-state-business-primary,#4d6bfe)}
804
805
  .ghp3-body{display:flex;flex-direction:column;flex:1;min-width:0;padding:8px 0}
805
806
  .ghp3-name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:14px;font-weight:500;line-height:22px;color:var(--dsw-alias-label-primary)}
@@ -811,53 +812,46 @@ var PENDING_CSS = `
811
812
  @media (prefers-reduced-motion:reduce){.ghp3-remove{transition:none}}
812
813
  `.trim();
813
814
  function GitHubPendingCard(props) {
814
- const { card, t, onOpenPanel, onRemove } = props;
815
+ const { card, t, onRemove } = props;
815
816
  const ref = `${card.repo}#${String(card.number)}`;
816
817
  const state = t(stateLabelKey(card.state));
817
818
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ghp3-rail", "data-github-pending": true, children: [
818
819
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StyleSheet, { chunks: [CONTROLS_CSS, PENDING_CSS] }),
819
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
820
- "div",
821
- {
822
- className: "ghp3-card",
823
- role: "button",
824
- tabIndex: 0,
825
- "aria-label": `${ref} \xB7 ${card.title}`,
826
- title: `${ref} \xB7 ${card.title}
820
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ghp3-card", children: [
821
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
822
+ "a",
823
+ {
824
+ className: "ghp3-link",
825
+ href: card.url,
826
+ target: "_blank",
827
+ rel: "noreferrer noopener",
828
+ "aria-label": `${ref} \xB7 ${card.title}`,
829
+ title: `${ref} \xB7 ${card.title}
827
830
  ${t("pending.tip")}`,
828
- onClick: onOpenPanel,
829
- onKeyDown: (event) => {
830
- if (event.target !== event.currentTarget) return;
831
- if (event.key !== "Enter" && event.key !== " ") return;
832
- event.preventDefault();
833
- onOpenPanel();
834
- },
835
- children: [
836
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ghp3-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GitHubIcon, { size: 16 }) }),
837
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ghp3-body", children: [
838
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ghp3-name", children: ref }),
839
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ghp3-meta", children: [
840
- state,
841
- " \xB7 ",
842
- card.title === "" ? t("pending.noTitle") : card.title
831
+ children: [
832
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ghp3-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GitHubIcon, { size: 16 }) }),
833
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ghp3-body", children: [
834
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ghp3-name", children: ref }),
835
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ghp3-meta", children: [
836
+ state,
837
+ " \xB7 ",
838
+ card.title === "" ? t("pending.noTitle") : card.title
839
+ ] })
843
840
  ] })
844
- ] }),
845
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
846
- "button",
847
- {
848
- type: "button",
849
- className: "ghp3-remove",
850
- "aria-label": t("dock.removeDraft"),
851
- onClick: (event) => {
852
- event.stopPropagation();
853
- onRemove();
854
- },
855
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseGlyph, { size: 12 })
856
- }
857
- )
858
- ]
859
- }
860
- )
841
+ ]
842
+ }
843
+ ),
844
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
845
+ "button",
846
+ {
847
+ type: "button",
848
+ className: "ghp3-remove",
849
+ "aria-label": t("dock.removeDraft"),
850
+ onClick: onRemove,
851
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseGlyph, { size: 12 })
852
+ }
853
+ )
854
+ ] })
861
855
  ] });
862
856
  }
863
857
 
@@ -5359,7 +5353,6 @@ function PendingOverlayHost({ store, t, sessionId, useInput, inputActions }) {
5359
5353
  const [pending, setPending] = (0, import_react5.useState)(void 0);
5360
5354
  const sending = (0, import_react5.useRef)(false);
5361
5355
  const stagedFor = (0, import_react5.useRef)(void 0);
5362
- const repairedFor = (0, import_react5.useRef)(void 0);
5363
5356
  const sawSentinel = (0, import_react5.useRef)(false);
5364
5357
  const input = useInput === void 0 ? void 0 : useInput((state) => state);
5365
5358
  const latestInput = (0, import_react5.useRef)(input);
@@ -5386,16 +5379,8 @@ function PendingOverlayHost({ store, t, sessionId, useInput, inputActions }) {
5386
5379
  }
5387
5380
  }, [card, draft, inputActions, pending?.id, sessionId, snapshot.pendingHandoffSession]);
5388
5381
  (0, import_react5.useEffect)(() => {
5389
- if (draft.includes(PENDING_DRAFT_SENTINEL)) {
5390
- sawSentinel.current = true;
5391
- return;
5392
- }
5393
- if (pending === void 0 || inputActions === void 0 || sending.current) return;
5394
- if (draft === "") return;
5395
- if (repairedFor.current === draft) return;
5396
- repairedFor.current = draft;
5397
- inputActions.setDraft(`${PENDING_DRAFT_SENTINEL}${draft}`);
5398
- }, [draft, inputActions, pending]);
5382
+ if (draft.includes(PENDING_DRAFT_SENTINEL)) sawSentinel.current = true;
5383
+ }, [draft]);
5399
5384
  (0, import_react5.useEffect)(() => {
5400
5385
  if (pending === void 0 || draft !== "" || !sawSentinel.current || sending.current) return;
5401
5386
  setPending(void 0);
@@ -5479,7 +5464,6 @@ function PendingOverlayHost({ store, t, sessionId, useInput, inputActions }) {
5479
5464
  {
5480
5465
  card: pending,
5481
5466
  t,
5482
- onOpenPanel: () => store.openInPanel(pending),
5483
5467
  onRemove: () => {
5484
5468
  inputActions?.setDraft("");
5485
5469
  setPending(void 0);
@@ -5938,6 +5922,47 @@ function remoteContribution() {
5938
5922
  };
5939
5923
  }
5940
5924
 
5925
+ // src/client/reference.ts
5926
+ var ISSUE_HEADING = /处理 GitHub Issue:([A-Za-z0-9_.\-]+\/[A-Za-z0-9_.\-]+)#([1-9][0-9]*)(?:[ \t]+([^\n]+))?/g;
5927
+ var STATE_TABLE = /\|\s*状态\s*\|\s*([^|\n]+?)\s*\|/u;
5928
+ var STATE_LEGACY = /状态:([^\n||]+)/u;
5929
+ function stateOf(text2) {
5930
+ const table = STATE_TABLE.exec(text2);
5931
+ if (table?.[1] !== void 0) return table[1].trim();
5932
+ const legacy = STATE_LEGACY.exec(text2);
5933
+ return legacy?.[1]?.trim();
5934
+ }
5935
+ var GITHUB_ISSUE_RULE = {
5936
+ id: "github-issue",
5937
+ order: 40,
5938
+ match(text2, from) {
5939
+ ISSUE_HEADING.lastIndex = from;
5940
+ for (let match = ISSUE_HEADING.exec(text2); match !== null; match = ISSUE_HEADING.exec(text2)) {
5941
+ if (match.index !== 0 && text2[match.index - 1] !== "\n") continue;
5942
+ const repo = match[1];
5943
+ const numberText = match[2];
5944
+ if (repo === void 0 || numberText === void 0) continue;
5945
+ const number = Number(numberText);
5946
+ if (!Number.isInteger(number) || number <= 0) continue;
5947
+ const title = match[3]?.trim();
5948
+ const state = stateOf(text2);
5949
+ return {
5950
+ id: "github-issue",
5951
+ start: match.index,
5952
+ end: match.index + match[0].length,
5953
+ data: {
5954
+ repo,
5955
+ number,
5956
+ url: `https://github.com/${repo}/issues/${String(number)}`,
5957
+ ...title === void 0 || title === "" ? {} : { title },
5958
+ ...state === void 0 || state === "" ? {} : { state }
5959
+ }
5960
+ };
5961
+ }
5962
+ return void 0;
5963
+ }
5964
+ };
5965
+
5941
5966
  // src/client/result.ts
5942
5967
  var RemoteRefusal = class extends Error {
5943
5968
  code;
@@ -6806,6 +6831,44 @@ var GitHubStore = class {
6806
6831
  }
6807
6832
  };
6808
6833
 
6834
+ // src/client/views/IssueReference.tsx
6835
+ var import_jsx_runtime12 = require("react/jsx-runtime");
6836
+ var ISSUE_REFERENCE_CSS = `
6837
+ .ghx-issue-card{display:inline-flex;align-items:center;gap:10px;box-sizing:border-box;width:240px;max-width:100%;height:64px;padding:0 12px;border:0.5px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:var(--dsw-radius-lg,12px);background:var(--dsw-specific-input-major,var(--dsw-alias-bg-base));color:var(--dsw-alias-label-primary);text-decoration:none;vertical-align:middle;font-family:inherit;margin:6px 0}
6838
+ .ghx-issue-card:hover{border-color:var(--dsw-alias-border-l3,rgba(0,0,0,.18))}
6839
+ .ghx-issue-card:focus-visible{outline:2px solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}
6840
+ .ghx-issue-icon{flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--dsw-radius-md,8px);background:color-mix(in srgb,var(--dsw-alias-state-business-primary,#4d6bfe) 12%,transparent);color:var(--dsw-alias-state-business-primary,#4d6bfe)}
6841
+ .ghx-issue-body{display:flex;flex-direction:column;flex:1;min-width:0}
6842
+ .ghx-issue-name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:14px;font-weight:500;line-height:22px}
6843
+ .ghx-issue-meta{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:12px;line-height:15px;color:var(--dsw-alias-label-tertiary,#8a9099)}
6844
+ `.trim();
6845
+ function GitHubIssueReference(props) {
6846
+ const { repo, number, url, title, state } = props.node.data;
6847
+ const ref = `${repo}#${String(number)}`;
6848
+ const meta = [state, title].filter((part) => part !== void 0 && part !== "").join(" \xB7 ");
6849
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
6850
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(StyleSheet, { chunks: [ISSUE_REFERENCE_CSS] }),
6851
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
6852
+ "a",
6853
+ {
6854
+ className: "ghx-issue-card",
6855
+ href: url,
6856
+ target: "_blank",
6857
+ rel: "noreferrer noopener",
6858
+ title: ref,
6859
+ "aria-label": ref,
6860
+ children: [
6861
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ghx-issue-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(GitHubIcon, { size: 16 }) }),
6862
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "ghx-issue-body", children: [
6863
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ghx-issue-name", children: ref }),
6864
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ghx-issue-meta", children: meta === "" ? "GitHub Issue" : meta })
6865
+ ] })
6866
+ ]
6867
+ }
6868
+ )
6869
+ ] });
6870
+ }
6871
+
6809
6872
  // src/client/index.tsx
6810
6873
  var PANEL_ID = "github";
6811
6874
  var SETTINGS_ID = "github-issues";
@@ -6870,6 +6933,17 @@ function apply3(ctx) {
6870
6933
  locale: NS,
6871
6934
  inject: () => ({ store, t })
6872
6935
  }, DropZoneHost));
6936
+ ctx.inject(["uiConversation"], (scoped) => {
6937
+ const conversation = scoped.uiConversation;
6938
+ if (conversation?.userText === void 0) return;
6939
+ scoped.effect(() => conversation.userText.register(GITHUB_ISSUE_RULE), "github-issues: user-text rule");
6940
+ scoped.slots.inject("conversation.user.text.node", () => scoped.slots.register({
6941
+ name: "conversation.user.text.node",
6942
+ key: "github-issue",
6943
+ priority: 100,
6944
+ locale: NS
6945
+ }, GitHubIssueReference));
6946
+ });
6873
6947
  ctx.inject(["sidebarRightTabs"], (scoped) => {
6874
6948
  const tabs = scoped.sidebarRightTabs;
6875
6949
  scoped.effect(() => tabs.register({
package/lib/prompt.js CHANGED
@@ -69,16 +69,16 @@ export function renderPrompt(issue, template) {
69
69
  return text;
70
70
  }
71
71
  /**
72
- * The invisible draft marker that keeps the native send enabled and lets the
73
- * pending card survive a Session/Workspace transfer.
72
+ * The draft marker that keeps the pending card recoverable and lets triggers work.
74
73
  *
75
- * DSH transfers the draft text when the composer switches Workspace, so keeping
76
- * this marker in the draft is what lets the new Session's composer find the card
77
- * again. `U+2063` (invisible separator) plus a zero-width space is invisible and
78
- * non-whitespace, so the composer treats the draft as occupied without showing
79
- * characters.
74
+ * It is a single hair space (`U+200A`): effectively invisible, but Unicode
75
+ * whitespace. That matters twice over: the composer treats the draft as occupied
76
+ * so native sends are not refused, and a `/command` or `@reference` typed after
77
+ * the card is preceded by whitespace, so the input trigger pipeline sees a token
78
+ * boundary. The old non-whitespace marker made commands fail unless the user
79
+ * typed an extra space.
80
80
  */
81
- export const PENDING_DRAFT_SENTINEL = '\u2063\u200b';
81
+ export const PENDING_DRAFT_SENTINEL = '\u200a';
82
82
  /** Backwards-compatible name for the marker the old overlay used. */
83
83
  export const EMPTY_DRAFT_HOLD = PENDING_DRAFT_SENTINEL;
84
84
  /**
@@ -94,7 +94,7 @@ export const EMPTY_DRAFT_HOLD = PENDING_DRAFT_SENTINEL;
94
94
  export function composeHandoffPrompt(prompt, memo) {
95
95
  const extra = memo
96
96
  .split(PENDING_DRAFT_SENTINEL).join('')
97
- .replace(/[\u200b\u200c\u200d\u2060\ufeff]/g, '')
97
+ .replace(/[\u200b\u200c\u200d\u2060\u2063\ufeff]/g, '')
98
98
  .replace(/^\n+/, '')
99
99
  .trim();
100
100
  return extra === '' ? prompt : `${prompt}\n\n${extra}`;
package/lib/prompt.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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"}
@@ -15,18 +15,18 @@ import type { PromptIssue } from './github/types.ts';
15
15
  */
16
16
  export declare function renderPrompt(issue: PromptIssue, template: string): string;
17
17
  /**
18
- * The invisible draft marker that keeps the native send enabled and lets the
19
- * pending card survive a Session/Workspace transfer.
18
+ * The draft marker that keeps the pending card recoverable and lets triggers work.
20
19
  *
21
- * DSH transfers the draft text when the composer switches Workspace, so keeping
22
- * this marker in the draft is what lets the new Session's composer find the card
23
- * again. `U+2063` (invisible separator) plus a zero-width space is invisible and
24
- * non-whitespace, so the composer treats the draft as occupied without showing
25
- * characters.
20
+ * It is a single hair space (`U+200A`): effectively invisible, but Unicode
21
+ * whitespace. That matters twice over: the composer treats the draft as occupied
22
+ * so native sends are not refused, and a `/command` or `@reference` typed after
23
+ * the card is preceded by whitespace, so the input trigger pipeline sees a token
24
+ * boundary. The old non-whitespace marker made commands fail unless the user
25
+ * typed an extra space.
26
26
  */
27
- export declare const PENDING_DRAFT_SENTINEL = "\u2063\u200B";
27
+ export declare const PENDING_DRAFT_SENTINEL = "\u200A";
28
28
  /** Backwards-compatible name for the marker the old overlay used. */
29
- export declare const EMPTY_DRAFT_HOLD = "\u2063\u200B";
29
+ export declare const EMPTY_DRAFT_HOLD = "\u200A";
30
30
  /**
31
31
  * Compose the message a pending issue card sends.
32
32
  *
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA0CpD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAezE;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,iBAAiB,CAAA;AAEpD,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,iBAAyB,CAAA;AAEtD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAOzE"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA0CpD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAezE;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,WAAW,CAAA;AAE9C,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,WAAyB,CAAA;AAEtD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAOzE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-github-issues",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Browse GitHub issues, milestones, labels, priority, and linked PR status inside DeepSeek Harness, and hand an issue to the agent by dragging it into the composer.",
5
5
  "keywords": [
6
6
  "dsh-plugin",