copilot-tap-extension 2.0.8 → 2.0.9

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.
Files changed (54) hide show
  1. package/README.md +2 -1
  2. package/SOUL.md +51 -0
  3. package/bin/install.mjs +2 -1
  4. package/dist/copilot-instructions.md +5 -0
  5. package/dist/extension.mjs +361 -20
  6. package/dist/version.json +1 -1
  7. package/docs/adr/0001-persistent-config-default-ownership.md +33 -0
  8. package/docs/adr/0002-local-provider-gateway-runtime-security.md +36 -0
  9. package/docs/adr/0003-emitter-delivery-lifecycle.md +68 -0
  10. package/docs/adr/0004-persistent-config-canonical-streams.md +86 -0
  11. package/docs/adr/0005-provider-sdk-push-and-dynamic-tools.md +48 -0
  12. package/docs/adr/0006-command-emitter-cwd-workspace-boundary.md +46 -0
  13. package/docs/adr/0007-runtime-session-workspace-context.md +62 -0
  14. package/docs/evals.md +41 -0
  15. package/docs/evolution-of-tap-icon.html +989 -0
  16. package/docs/providers.md +242 -0
  17. package/docs/recipes/adaptive-agent.md +303 -0
  18. package/docs/recipes/agent-brainstorm/100-extension-ideas.md +288 -0
  19. package/docs/recipes/agent-brainstorm/deep-ideas.md +216 -0
  20. package/docs/recipes/ambient-guardian.md +314 -0
  21. package/docs/recipes/browser-bridge.md +162 -0
  22. package/docs/recipes/codex-goals-for-tap-goal.md +136 -0
  23. package/docs/recipes/copilot-sdk-canvas.md +147 -0
  24. package/docs/recipes/deferred-cognition.md +310 -0
  25. package/docs/recipes/provider-integration-patterns.md +93 -0
  26. package/docs/recipes/provider-interface-advanced.md +1364 -0
  27. package/docs/recipes/provider-interface-core-profile.md +568 -0
  28. package/docs/recipes/tap-control-plane-roadmap.md +60 -0
  29. package/docs/recipes/universal-tool-gateway.md +202 -0
  30. package/docs/reference.md +229 -0
  31. package/docs/use-cases.md +348 -0
  32. package/package.json +4 -1
  33. package/providers/detour/README.md +84 -0
  34. package/providers/detour/bridge.js +219 -0
  35. package/providers/detour/index.mjs +322 -0
  36. package/providers/detour/package-lock.json +577 -0
  37. package/providers/detour/package.json +19 -0
  38. package/providers/detour/scripts/build.mjs +31 -0
  39. package/providers/detour/src/bridge.js +256 -0
  40. package/providers/detour/src/contracts.js +40 -0
  41. package/providers/detour/src/inspector.js +260 -0
  42. package/providers/detour/src/inspector.test.mjs +53 -0
  43. package/providers/detour/src/panel.js +465 -0
  44. package/providers/detour/src/provider-core.js +233 -0
  45. package/providers/detour/src/provider-core.test.mjs +185 -0
  46. package/providers/detour/src/react-context-core.js +143 -0
  47. package/providers/detour/src/react-context.js +44 -0
  48. package/providers/detour/src/react-context.test.mjs +41 -0
  49. package/providers/templates/README.md +23 -0
  50. package/providers/templates/ci-review-provider.mjs +46 -0
  51. package/providers/templates/detour-workflow-provider.mjs +41 -0
  52. package/providers/templates/jira-github-provider.mjs +42 -0
  53. package/providers/templates/provider-utils.mjs +45 -0
  54. package/providers/templates/sast-triage-provider.mjs +51 -0
@@ -0,0 +1,46 @@
1
+ import { connectProvider, push } from "./provider-utils.mjs";
2
+
3
+ const tools = [
4
+ {
5
+ name: "ci_review_normalize_findings",
6
+ description: "Normalize structured code review findings into tap provider events.",
7
+ parameters: {
8
+ type: "object",
9
+ properties: {
10
+ findings: { type: "array" },
11
+ runUrl: { type: "string" },
12
+ repository: { type: "string" }
13
+ },
14
+ required: ["findings"]
15
+ }
16
+ }
17
+ ];
18
+
19
+ connectProvider({
20
+ name: "ci-review-template",
21
+ tools,
22
+ onMessage(ws, msg) {
23
+ if (msg.type !== "tool.call" || msg.tool !== "ci_review_normalize_findings") {
24
+ return;
25
+ }
26
+ const args = msg.arguments ?? {};
27
+ for (const finding of args.findings ?? []) {
28
+ const priority = Number(finding.priority ?? 3);
29
+ push(ws, {
30
+ stream: "ci-review",
31
+ level: priority <= 1 ? "inject" : "surface",
32
+ event: {
33
+ type: "review.finding",
34
+ title: finding.title,
35
+ priority,
36
+ confidence: finding.confidence_score,
37
+ file: finding.code_location?.absolute_file_path,
38
+ line: finding.code_location?.line_range?.start,
39
+ runUrl: args.runUrl,
40
+ repository: args.repository
41
+ }
42
+ });
43
+ }
44
+ ws.send(JSON.stringify({ type: "tool.result", callId: msg.callId, result: { ok: true } }));
45
+ }
46
+ });
@@ -0,0 +1,41 @@
1
+ import { connectProvider, push } from "./provider-utils.mjs";
2
+
3
+ const tools = [
4
+ {
5
+ name: "detour_emit_page_event",
6
+ description: "Normalize browser or Detour page events for tap streams.",
7
+ parameters: {
8
+ type: "object",
9
+ properties: {
10
+ url: { type: "string" },
11
+ eventType: { type: "string" },
12
+ message: { type: "string" },
13
+ severity: { type: "string" }
14
+ },
15
+ required: ["eventType", "message"]
16
+ }
17
+ }
18
+ ];
19
+
20
+ connectProvider({
21
+ name: "detour-workflow-template",
22
+ tools,
23
+ onMessage(ws, msg) {
24
+ if (msg.type !== "tool.call" || msg.tool !== "detour_emit_page_event") {
25
+ return;
26
+ }
27
+ const args = msg.arguments ?? {};
28
+ const severity = String(args.severity ?? "info").toLowerCase();
29
+ push(ws, {
30
+ stream: "detour-browser",
31
+ level: /error|fatal|blocked/.test(severity) ? "inject" : "surface",
32
+ event: {
33
+ type: `browser.${args.eventType}`,
34
+ url: args.url ?? null,
35
+ severity,
36
+ message: args.message
37
+ }
38
+ });
39
+ ws.send(JSON.stringify({ type: "tool.result", callId: msg.callId, result: { ok: true } }));
40
+ }
41
+ });
@@ -0,0 +1,42 @@
1
+ import { connectProvider, push } from "./provider-utils.mjs";
2
+
3
+ const tools = [
4
+ {
5
+ name: "jira_github_emit_issue",
6
+ description: "Emit a normalized Jira issue event for tap goals or orchestration.",
7
+ parameters: {
8
+ type: "object",
9
+ properties: {
10
+ issueKey: { type: "string" },
11
+ summary: { type: "string" },
12
+ description: { type: "string" },
13
+ label: { type: "string" },
14
+ prUrl: { type: "string" }
15
+ },
16
+ required: ["issueKey", "summary"]
17
+ }
18
+ }
19
+ ];
20
+
21
+ connectProvider({
22
+ name: "jira-github-template",
23
+ tools,
24
+ onMessage(ws, msg) {
25
+ if (msg.type !== "tool.call" || msg.tool !== "jira_github_emit_issue") {
26
+ return;
27
+ }
28
+ const args = msg.arguments ?? {};
29
+ push(ws, {
30
+ stream: "jira-github",
31
+ level: "inject",
32
+ event: {
33
+ type: "jira.issue.ready",
34
+ issueKey: args.issueKey,
35
+ summary: args.summary,
36
+ label: args.label,
37
+ prUrl: args.prUrl ?? null
38
+ }
39
+ });
40
+ ws.send(JSON.stringify({ type: "tool.result", callId: msg.callId, result: { ok: true } }));
41
+ }
42
+ });
@@ -0,0 +1,45 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import WebSocket from "ws";
5
+
6
+ export function discoverTapToken() {
7
+ if (process.env.TAP_PROVIDER_TOKEN) {
8
+ return process.env.TAP_PROVIDER_TOKEN;
9
+ }
10
+ const copilotHome = process.env.COPILOT_HOME || path.join(os.homedir(), ".copilot");
11
+ return fs.readFileSync(path.join(copilotHome, "extensions", "tap", ".provider-token"), "utf8").trim();
12
+ }
13
+
14
+ export function connectProvider({ name, tools, session = "all", onMessage }) {
15
+ const token = discoverTapToken();
16
+ const ws = new WebSocket(process.env.TAP_PROVIDER_URL || "ws://127.0.0.1:9400");
17
+ ws.on("open", () => {
18
+ ws.send(JSON.stringify({ type: "auth", token }));
19
+ });
20
+ ws.on("message", (raw) => {
21
+ const msg = JSON.parse(String(raw));
22
+ if (msg.type === "sessions") {
23
+ ws.send(JSON.stringify({
24
+ type: "hello",
25
+ name,
26
+ protocolVersion: 2,
27
+ session,
28
+ tools
29
+ }));
30
+ return;
31
+ }
32
+ onMessage?.(ws, msg);
33
+ });
34
+ return ws;
35
+ }
36
+
37
+ export function push(ws, { stream, level = "surface", event, metadata = {} }) {
38
+ ws.send(JSON.stringify({
39
+ type: "push",
40
+ level,
41
+ stream,
42
+ event: typeof event === "string" ? event : JSON.stringify(event),
43
+ metadata
44
+ }));
45
+ }
@@ -0,0 +1,51 @@
1
+ import { createHash } from "node:crypto";
2
+ import { connectProvider, push } from "./provider-utils.mjs";
3
+
4
+ function fingerprint(finding) {
5
+ return createHash("sha256")
6
+ .update([finding.cwe, finding.sink, finding.file, finding.line].filter(Boolean).join("|"))
7
+ .digest("hex")
8
+ .slice(0, 16);
9
+ }
10
+
11
+ const tools = [
12
+ {
13
+ name: "sast_emit_findings",
14
+ description: "Normalize SAST findings into stable, fingerprinted tap events.",
15
+ parameters: {
16
+ type: "object",
17
+ properties: {
18
+ findings: { type: "array" }
19
+ },
20
+ required: ["findings"]
21
+ }
22
+ }
23
+ ];
24
+
25
+ connectProvider({
26
+ name: "sast-triage-template",
27
+ tools,
28
+ onMessage(ws, msg) {
29
+ if (msg.type !== "tool.call" || msg.tool !== "sast_emit_findings") {
30
+ return;
31
+ }
32
+ for (const finding of msg.arguments?.findings ?? []) {
33
+ const severity = String(finding.severity ?? "medium").toLowerCase();
34
+ push(ws, {
35
+ stream: "sast-triage",
36
+ level: /critical|high/.test(severity) ? "inject" : "surface",
37
+ event: {
38
+ type: "sast.finding",
39
+ fingerprint: fingerprint(finding),
40
+ severity,
41
+ cwe: finding.cwe,
42
+ file: finding.file,
43
+ line: finding.line,
44
+ sink: finding.sink,
45
+ exploitability: finding.exploitability ?? null
46
+ }
47
+ });
48
+ }
49
+ ws.send(JSON.stringify({ type: "tool.result", callId: msg.callId, result: { ok: true } }));
50
+ }
51
+ });