源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
import { mergeAttributes, Node } from "@tiptap/core";
|
||||
|
||||
export interface AgentCapabilityTokenOption {
|
||||
capability: string;
|
||||
label: string;
|
||||
name: string;
|
||||
trigger: string;
|
||||
}
|
||||
|
||||
export interface AgentCapabilityTokenAttrs {
|
||||
capability: string;
|
||||
label: string;
|
||||
name: string;
|
||||
trigger: string;
|
||||
}
|
||||
|
||||
export interface AgentCapabilityTokenMatch {
|
||||
attrs: AgentCapabilityTokenAttrs;
|
||||
end: number;
|
||||
}
|
||||
|
||||
export interface AgentCapabilityTokenExtensionOptions {
|
||||
capabilities?: readonly AgentCapabilityTokenOption[];
|
||||
}
|
||||
|
||||
export function createAgentCapabilityTokenExtension(
|
||||
options: AgentCapabilityTokenExtensionOptions = {}
|
||||
): Node {
|
||||
return Node.create({
|
||||
name: "agentCapabilityToken",
|
||||
group: "inline",
|
||||
inline: true,
|
||||
atom: true,
|
||||
selectable: true,
|
||||
|
||||
addOptions() {
|
||||
return options;
|
||||
},
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
capability: { default: "" },
|
||||
label: { default: "" },
|
||||
name: { default: "" },
|
||||
trigger: { default: "" }
|
||||
};
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [{ tag: "span[data-agent-capability-token]" }];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
const attrs = attrsToCapabilityTokenAttrs(HTMLAttributes);
|
||||
const displayLabel = capabilityTokenDisplayLabel(attrs);
|
||||
return [
|
||||
"span",
|
||||
mergeAttributes(HTMLAttributes, {
|
||||
"aria-label": attrs.label,
|
||||
contentEditable: "false",
|
||||
"data-agent-capability-token": "true",
|
||||
"data-agent-capability-trigger": attrs.trigger,
|
||||
"data-agent-mention-kind": "capability",
|
||||
class: "tsh-agent-object-token tsh-agent-object-token--entity"
|
||||
}),
|
||||
[
|
||||
"span",
|
||||
{
|
||||
class: "tsh-agent-object-token__kind",
|
||||
"aria-hidden": "true"
|
||||
},
|
||||
[
|
||||
"span",
|
||||
{
|
||||
class: "tsh-agent-object-token__kind-icon",
|
||||
"aria-hidden": "true"
|
||||
},
|
||||
""
|
||||
]
|
||||
],
|
||||
["span", { class: "tsh-agent-object-token__main" }, displayLabel]
|
||||
];
|
||||
},
|
||||
|
||||
renderText({ node }) {
|
||||
return attrsToCapabilityTokenAttrs(node.attrs ?? {}).trigger;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function parseAgentCapabilityToken(
|
||||
text: string,
|
||||
start: number,
|
||||
capabilities: readonly AgentCapabilityTokenOption[] = []
|
||||
): AgentCapabilityTokenMatch | null {
|
||||
if (!isCapabilityTokenBoundary(text[start - 1] ?? "")) {
|
||||
return null;
|
||||
}
|
||||
for (const candidate of capabilityTokenCandidates(capabilities)) {
|
||||
if (!text.startsWith(candidate.trigger, start)) {
|
||||
continue;
|
||||
}
|
||||
const end = start + candidate.trigger.length;
|
||||
if (!isCapabilityTokenBoundary(text[end] ?? "")) {
|
||||
continue;
|
||||
}
|
||||
return {
|
||||
attrs: candidate,
|
||||
end
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function capabilityTokenCandidates(
|
||||
capabilities: readonly AgentCapabilityTokenOption[]
|
||||
): AgentCapabilityTokenAttrs[] {
|
||||
const candidates = new Map<string, AgentCapabilityTokenAttrs>();
|
||||
for (const capability of capabilities) {
|
||||
const trigger = capability.trigger.trim();
|
||||
if (!trigger || candidates.has(trigger)) {
|
||||
continue;
|
||||
}
|
||||
candidates.set(trigger, {
|
||||
capability: capability.capability.trim(),
|
||||
label: capability.label.trim(),
|
||||
name: capability.name.trim(),
|
||||
trigger
|
||||
});
|
||||
}
|
||||
return [...candidates.values()].sort(
|
||||
(left, right) => right.trigger.length - left.trigger.length
|
||||
);
|
||||
}
|
||||
|
||||
function isCapabilityTokenBoundary(value: string): boolean {
|
||||
return value === "" || value === " " || value === "\n" || value === "\t";
|
||||
}
|
||||
|
||||
function attrsToCapabilityTokenAttrs(
|
||||
attrs: Record<string, unknown>
|
||||
): AgentCapabilityTokenAttrs {
|
||||
return {
|
||||
capability: typeof attrs.capability === "string" ? attrs.capability : "",
|
||||
label: typeof attrs.label === "string" ? attrs.label : "",
|
||||
name: typeof attrs.name === "string" ? attrs.name : "",
|
||||
trigger: typeof attrs.trigger === "string" ? attrs.trigger : ""
|
||||
};
|
||||
}
|
||||
|
||||
function capabilityTokenDisplayLabel(attrs: AgentCapabilityTokenAttrs): string {
|
||||
const label = attrs.label.trim() || attrs.trigger.trim();
|
||||
if (!label || label.startsWith("/") || label.startsWith("$")) {
|
||||
return label;
|
||||
}
|
||||
return `/${label}`;
|
||||
}
|
||||
Reference in New Issue
Block a user