@takuhon/core 0.12.0 → 0.14.0
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/dist/index.d.ts +199 -1
- package/dist/index.js +191 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3712,6 +3712,204 @@ declare class ConflictError extends StorageError {
|
|
|
3712
3712
|
*/
|
|
3713
3713
|
declare function renderActivitySvg(snapshot: ActivitySnapshot): string;
|
|
3714
3714
|
|
|
3715
|
+
/**
|
|
3716
|
+
* Résumé / CV projection of a profile.
|
|
3717
|
+
*
|
|
3718
|
+
* {@link deriveCv} turns one locale-resolved {@link LocalizedTakuhon} into a
|
|
3719
|
+
* {@link CvDocument}: a header plus the CV-relevant sections in a fixed,
|
|
3720
|
+
* résumé-conventional order. It is a pure, deterministic selection-and-projection
|
|
3721
|
+
* — no clock, no randomness, no I/O — so the static export ({@link
|
|
3722
|
+
* import('@takuhon/cli')}) and a React `CvView` render identical output from the
|
|
3723
|
+
* same input.
|
|
3724
|
+
*
|
|
3725
|
+
* A CV is a curated *subset* of the profile: the web-page-specific sections
|
|
3726
|
+
* (links, recommendations, the activity dashboard, test scores) are omitted,
|
|
3727
|
+
* and the rest appear in the order a résumé conventionally uses. Entry order
|
|
3728
|
+
* within a section is preserved from the input (already normalized by `order`
|
|
3729
|
+
* upstream), so the owner's `order` field controls it — `deriveCv` never
|
|
3730
|
+
* re-sorts. Empty sections are dropped so the renderer can iterate without
|
|
3731
|
+
* emptiness checks.
|
|
3732
|
+
*
|
|
3733
|
+
* The input must already be privacy-filtered (`applyPublicPrivacyFilter`) by the
|
|
3734
|
+
* caller, exactly as the public render path is: `deriveCv` does not strip
|
|
3735
|
+
* anything itself, it only projects what it is given.
|
|
3736
|
+
*/
|
|
3737
|
+
|
|
3738
|
+
/** The header block of a CV: identity and contact, drawn from `profile` + `contact`. */
|
|
3739
|
+
interface CvHeader {
|
|
3740
|
+
displayName: string;
|
|
3741
|
+
tagline?: string;
|
|
3742
|
+
/** Human-readable location (the address `display` string), if present. */
|
|
3743
|
+
location?: string;
|
|
3744
|
+
bio?: string;
|
|
3745
|
+
/** Email, only when the profile exposed it (privacy filter already applied). */
|
|
3746
|
+
email?: string;
|
|
3747
|
+
formUrl?: string;
|
|
3748
|
+
}
|
|
3749
|
+
/**
|
|
3750
|
+
* One CV section, discriminated by `kind`, carrying the locale-resolved entries
|
|
3751
|
+
* for that section. The entry types are reused verbatim from `LocalizedTakuhon`.
|
|
3752
|
+
*/
|
|
3753
|
+
type CvSection = {
|
|
3754
|
+
kind: 'experience';
|
|
3755
|
+
entries: LocalizedCareer[];
|
|
3756
|
+
} | {
|
|
3757
|
+
kind: 'education';
|
|
3758
|
+
entries: LocalizedEducation[];
|
|
3759
|
+
} | {
|
|
3760
|
+
kind: 'skills';
|
|
3761
|
+
entries: Skill[];
|
|
3762
|
+
} | {
|
|
3763
|
+
kind: 'certifications';
|
|
3764
|
+
entries: LocalizedCertification[];
|
|
3765
|
+
} | {
|
|
3766
|
+
kind: 'publications';
|
|
3767
|
+
entries: LocalizedPublication[];
|
|
3768
|
+
} | {
|
|
3769
|
+
kind: 'honors';
|
|
3770
|
+
entries: LocalizedHonor[];
|
|
3771
|
+
} | {
|
|
3772
|
+
kind: 'courses';
|
|
3773
|
+
entries: LocalizedCourse[];
|
|
3774
|
+
} | {
|
|
3775
|
+
kind: 'patents';
|
|
3776
|
+
entries: LocalizedPatent[];
|
|
3777
|
+
} | {
|
|
3778
|
+
kind: 'languages';
|
|
3779
|
+
entries: LocalizedLanguage[];
|
|
3780
|
+
} | {
|
|
3781
|
+
kind: 'volunteering';
|
|
3782
|
+
entries: LocalizedVolunteering[];
|
|
3783
|
+
} | {
|
|
3784
|
+
kind: 'memberships';
|
|
3785
|
+
entries: LocalizedMembership[];
|
|
3786
|
+
};
|
|
3787
|
+
/** Every `CvSection` discriminant, in the fixed résumé order `deriveCv` emits. */
|
|
3788
|
+
type CvSectionKind = CvSection['kind'];
|
|
3789
|
+
/** A résumé/CV view derived from a profile: a header plus ordered sections. */
|
|
3790
|
+
interface CvDocument {
|
|
3791
|
+
/** The locale this CV was resolved at (mirrors `LocalizedTakuhon.resolvedLocale`). */
|
|
3792
|
+
resolvedLocale: string;
|
|
3793
|
+
header: CvHeader;
|
|
3794
|
+
/** Non-empty sections only, in the fixed CV order. */
|
|
3795
|
+
sections: CvSection[];
|
|
3796
|
+
}
|
|
3797
|
+
/**
|
|
3798
|
+
* Project a locale-resolved profile into a {@link CvDocument}. Sections appear
|
|
3799
|
+
* in a fixed résumé-conventional order and empty ones are omitted; entry order
|
|
3800
|
+
* within each section is preserved from the input. Pure and deterministic.
|
|
3801
|
+
*/
|
|
3802
|
+
declare function deriveCv(localized: LocalizedTakuhon): CvDocument;
|
|
3803
|
+
|
|
3804
|
+
/**
|
|
3805
|
+
* MCP (Model Context Protocol) projection of a profile.
|
|
3806
|
+
*
|
|
3807
|
+
* This module describes how a takuhon profile is exposed to an AI agent as a
|
|
3808
|
+
* set of read-only MCP tools and resources, and how each one is answered from a
|
|
3809
|
+
* profile document — *without* committing to a transport (stdio / HTTP) or to
|
|
3810
|
+
* any MCP SDK.
|
|
3811
|
+
*
|
|
3812
|
+
* The split mirrors the rest of core: deciding *what* to expose and *what it
|
|
3813
|
+
* returns* is a pure, deterministic projection over the canonical document
|
|
3814
|
+
* (exactly like {@link generateJsonLd}), so it lives here in `@takuhon/core` and
|
|
3815
|
+
* stays runtime-free (spec §2.3). The transport, JSON-RPC framing, and server
|
|
3816
|
+
* lifecycle are runtime-aware; they live in `@takuhon/mcp` and the CLI /
|
|
3817
|
+
* Cloudflare adapters, which call the pure executors below.
|
|
3818
|
+
*
|
|
3819
|
+
* Everything here is read-only. No tool or resource touches the admin surface,
|
|
3820
|
+
* and every answer passes through {@link applyPublicPrivacyFilter}, so an MCP
|
|
3821
|
+
* client sees exactly what `GET /api/profile`, `GET /api/jsonld`, `GET
|
|
3822
|
+
* /api/schema`, and `GET /takuhon.json` already expose — no more.
|
|
3823
|
+
*
|
|
3824
|
+
* The catalog ({@link MCP_TOOLS} / {@link MCP_RESOURCES}) is plain data with no
|
|
3825
|
+
* SDK dependency, so the `@takuhon/mcp` wiring can register it against the
|
|
3826
|
+
* official `@modelcontextprotocol/sdk` and later be swapped to a hand-rolled
|
|
3827
|
+
* dispatcher without touching this file.
|
|
3828
|
+
*/
|
|
3829
|
+
|
|
3830
|
+
/**
|
|
3831
|
+
* Profile sections a `get_section` call may request: the content-bearing keys
|
|
3832
|
+
* of a locale-resolved profile (the spec §6 data sections). `settings`,
|
|
3833
|
+
* `meta`, `schemaVersion`, and `resolvedLocale` are intentionally excluded —
|
|
3834
|
+
* they are configuration / bookkeeping, not profile content an agent reads.
|
|
3835
|
+
*/
|
|
3836
|
+
declare const MCP_PROFILE_SECTIONS: readonly ["profile", "links", "careers", "projects", "skills", "certifications", "memberships", "volunteering", "honors", "education", "publications", "languages", "courses", "patents", "testScores", "recommendations", "contact"];
|
|
3837
|
+
/** One of the {@link MCP_PROFILE_SECTIONS} a `get_section` call accepts. */
|
|
3838
|
+
type McpProfileSection = (typeof MCP_PROFILE_SECTIONS)[number];
|
|
3839
|
+
/** A JSON Schema (draft 2020-12) object describing a tool's input arguments. */
|
|
3840
|
+
type McpInputSchema = Readonly<Record<string, unknown>>;
|
|
3841
|
+
/** A read-only MCP tool definition — plain data, no SDK dependency. */
|
|
3842
|
+
interface McpToolDefinition {
|
|
3843
|
+
/** Stable tool id used in `tools/call`. */
|
|
3844
|
+
name: string;
|
|
3845
|
+
/** Human-readable title for display. */
|
|
3846
|
+
title: string;
|
|
3847
|
+
/** What the tool returns; shown to the agent when it chooses a tool. */
|
|
3848
|
+
description: string;
|
|
3849
|
+
/** JSON Schema for the tool's `arguments` object. */
|
|
3850
|
+
inputSchema: McpInputSchema;
|
|
3851
|
+
}
|
|
3852
|
+
/** A read-only MCP resource definition — plain data, no SDK dependency. */
|
|
3853
|
+
interface McpResourceDefinition {
|
|
3854
|
+
/** Stable resource URI used in `resources/read`. */
|
|
3855
|
+
uri: string;
|
|
3856
|
+
name: string;
|
|
3857
|
+
title: string;
|
|
3858
|
+
description: string;
|
|
3859
|
+
/** MIME type of the resource contents. */
|
|
3860
|
+
mimeType: string;
|
|
3861
|
+
}
|
|
3862
|
+
/** Result of {@link executeMcpTool}: the structured value the tool produced. */
|
|
3863
|
+
interface McpToolResult {
|
|
3864
|
+
/**
|
|
3865
|
+
* The JSON value the tool produced — already normalized, locale-resolved, and
|
|
3866
|
+
* privacy-filtered. The transport layer serializes this to MCP wire content.
|
|
3867
|
+
*/
|
|
3868
|
+
data: unknown;
|
|
3869
|
+
/** Locale the result was resolved at, when the tool resolved one. */
|
|
3870
|
+
resolvedLocale?: string;
|
|
3871
|
+
}
|
|
3872
|
+
/** Result of {@link readMcpResource}: one resource's contents. */
|
|
3873
|
+
interface McpResourceResult {
|
|
3874
|
+
uri: string;
|
|
3875
|
+
mimeType: string;
|
|
3876
|
+
/** The JSON value of the resource. The transport layer serializes it. */
|
|
3877
|
+
data: unknown;
|
|
3878
|
+
}
|
|
3879
|
+
/**
|
|
3880
|
+
* Thrown by {@link executeMcpTool} / {@link readMcpResource} for an unknown
|
|
3881
|
+
* tool/resource name or invalid arguments. The transport layer maps it to the
|
|
3882
|
+
* appropriate MCP error (a JSON-RPC error for a malformed request, or an
|
|
3883
|
+
* `isError` tool result for a bad argument) — core stays transport-agnostic.
|
|
3884
|
+
*/
|
|
3885
|
+
declare class McpRequestError extends Error {
|
|
3886
|
+
constructor(message: string, options?: {
|
|
3887
|
+
cause?: unknown;
|
|
3888
|
+
});
|
|
3889
|
+
}
|
|
3890
|
+
/** The read-only tools an MCP client may call against the profile. */
|
|
3891
|
+
declare const MCP_TOOLS: readonly McpToolDefinition[];
|
|
3892
|
+
/** The read-only resources an MCP client may read. */
|
|
3893
|
+
declare const MCP_RESOURCES: readonly McpResourceDefinition[];
|
|
3894
|
+
/**
|
|
3895
|
+
* Execute a read-only MCP tool against a profile document.
|
|
3896
|
+
*
|
|
3897
|
+
* `profile` is the raw validated {@link Takuhon} (the transport layer loaded it
|
|
3898
|
+
* from KV / a file). Locale-aware tools normalize, locale-resolve, and
|
|
3899
|
+
* privacy-filter it exactly as `GET /api/profile` does, then project the
|
|
3900
|
+
* requested view. Pure and deterministic — no clock, no randomness, no I/O.
|
|
3901
|
+
*
|
|
3902
|
+
* @throws {McpRequestError} for an unknown tool name or invalid arguments.
|
|
3903
|
+
*/
|
|
3904
|
+
declare function executeMcpTool(name: string, args: Readonly<Record<string, unknown>>, profile: Takuhon): McpToolResult;
|
|
3905
|
+
/**
|
|
3906
|
+
* Read a read-only MCP resource from a profile document. Pure and
|
|
3907
|
+
* deterministic.
|
|
3908
|
+
*
|
|
3909
|
+
* @throws {McpRequestError} for an unknown resource URI.
|
|
3910
|
+
*/
|
|
3911
|
+
declare function readMcpResource(uri: string, profile: Takuhon): McpResourceResult;
|
|
3912
|
+
|
|
3715
3913
|
/**
|
|
3716
3914
|
* Image-asset helpers for uploaded media (avatars, project images): magic-byte
|
|
3717
3915
|
* type detection, header-only dimension / frame reading, and metadata stripping
|
|
@@ -3812,4 +4010,4 @@ declare function stripImageMetadata(bytes: Uint8Array, mime: AcceptedImageMime):
|
|
|
3812
4010
|
*/
|
|
3813
4011
|
declare const SCHEMA_VERSION = "0.5.0";
|
|
3814
4012
|
|
|
3815
|
-
export { ACCEPTED_IMAGE_MIME_TYPES, type AcceptedImageMime, type ActivitySettings, type ActivitySnapshot, type ActivityStorage, type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, type CodingTime, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type ContributionCalendar, type ContributionDay, type Course, type Education, type ExportOptions, type ExportedTakuhon, type Honor, IMAGE_EXTENSIONS, type ImageInfo, ImportError, type Iso3166Alpha2, type IsoDateTime, type Language, type LanguageBreakdown, type LanguageProficiency, type Link, type LinkBuiltin, type LinkCustom, type LinkType, type LocaleTag, type LocalizedAddress, type LocalizedAvatar, type LocalizedBody, type LocalizedCareer, type LocalizedCertification, type LocalizedCourse, type LocalizedEducation, type LocalizedHonor, type LocalizedLanguage, type LocalizedLink, type LocalizedLinkBuiltin, type LocalizedLinkCustom, type LocalizedMembership, type LocalizedPatent, type LocalizedProfile, type LocalizedProject, type LocalizedPublication, type LocalizedRecommendation, type LocalizedRecommendationAuthor, type LocalizedTakuhon, type LocalizedTestScore, type LocalizedTitle, type LocalizedVolunteering, MAX_IMAGE_BYTES, MAX_IMAGE_DIMENSION, MAX_IMAGE_FRAMES, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Patent, type PatentStatus, type Profile, type Project, type Publication, RANK_FULL_CODING_HOURS, RANK_FULL_CONTRIBUTIONS, RANK_TIER_THRESHOLDS, type RankInput, type RankTier, type RankTierLabel, type Recommendation, type RecommendationAuthor, SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, type Schema, type Settings, type Skill, type Slug, StorageError, type Takuhon, type TakuhonAssetStorage, type TakuhonStorage, type TestScore, type ValidationError, type ValidationResult, type Volunteering, type YearMonth, applyPublicPrivacyFilter, computeLanguagePercentages, deriveRankTier, detectImageMime, exportTakuhon, formatCodingTime, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, importTakuhon, isActivitySnapshot, migrateTakuhon, migrations, normalize, readImageInfo, renderActivitySvg, resolveLocale, schema, stripImageMetadata, validate };
|
|
4013
|
+
export { ACCEPTED_IMAGE_MIME_TYPES, type AcceptedImageMime, type ActivitySettings, type ActivitySnapshot, type ActivityStorage, type Address, type AssetOptions, type AssetRecord, type Avatar, type Career, type Certification, type CodingTime, ConflictError, type Contact, type ContentLicense, type ContentLicenseAttribution, type ContributionCalendar, type ContributionDay, type Course, type CvDocument, type CvHeader, type CvSection, type CvSectionKind, type Education, type ExportOptions, type ExportedTakuhon, type Honor, IMAGE_EXTENSIONS, type ImageInfo, ImportError, type Iso3166Alpha2, type IsoDateTime, type Language, type LanguageBreakdown, type LanguageProficiency, type Link, type LinkBuiltin, type LinkCustom, type LinkType, type LocaleTag, type LocalizedAddress, type LocalizedAvatar, type LocalizedBody, type LocalizedCareer, type LocalizedCertification, type LocalizedCourse, type LocalizedEducation, type LocalizedHonor, type LocalizedLanguage, type LocalizedLink, type LocalizedLinkBuiltin, type LocalizedLinkCustom, type LocalizedMembership, type LocalizedPatent, type LocalizedProfile, type LocalizedProject, type LocalizedPublication, type LocalizedRecommendation, type LocalizedRecommendationAuthor, type LocalizedTakuhon, type LocalizedTestScore, type LocalizedTitle, type LocalizedVolunteering, MAX_IMAGE_BYTES, MAX_IMAGE_DIMENSION, MAX_IMAGE_FRAMES, MCP_PROFILE_SECTIONS, MCP_RESOURCES, MCP_TOOLS, type McpInputSchema, type McpProfileSection, McpRequestError, type McpResourceDefinition, type McpResourceResult, type McpToolDefinition, type McpToolResult, type Membership, type Meta, type MetaPrivacy, type Migration, MigrationError, type NormalizedTakuhon, NotFoundError, type Patent, type PatentStatus, type Profile, type Project, type Publication, RANK_FULL_CODING_HOURS, RANK_FULL_CONTRIBUTIONS, RANK_TIER_THRESHOLDS, type RankInput, type RankTier, type RankTierLabel, type Recommendation, type RecommendationAuthor, SCHEMA_VERSION, SUPPORTED_SCHEMA_VERSIONS, type Schema, type Settings, type Skill, type Slug, StorageError, type Takuhon, type TakuhonAssetStorage, type TakuhonStorage, type TestScore, type ValidationError, type ValidationResult, type Volunteering, type YearMonth, applyPublicPrivacyFilter, computeLanguagePercentages, deriveCv, deriveRankTier, detectImageMime, executeMcpTool, exportTakuhon, formatCodingTime, generateJsonLd, generatePersonJsonLd, generateProfilePageJsonLd, importTakuhon, isActivitySnapshot, migrateTakuhon, migrations, normalize, readImageInfo, readMcpResource, renderActivitySvg, resolveLocale, schema, stripImageMetadata, validate };
|
package/dist/index.js
CHANGED
|
@@ -11558,6 +11558,190 @@ function renderActivitySvg(snapshot) {
|
|
|
11558
11558
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${String(WIDTH)}" height="${String(height)}" viewBox="0 0 ${String(WIDTH)} ${String(height)}" role="img" aria-label="Developer activity"><title>Developer activity</title>${parts.join("")}</svg>`;
|
|
11559
11559
|
}
|
|
11560
11560
|
|
|
11561
|
+
// src/cv.ts
|
|
11562
|
+
function deriveCv(localized) {
|
|
11563
|
+
const p = localized.profile;
|
|
11564
|
+
const header = { displayName: p.displayName };
|
|
11565
|
+
if (p.tagline !== void 0) header.tagline = p.tagline;
|
|
11566
|
+
if (p.location?.display !== void 0) header.location = p.location.display;
|
|
11567
|
+
if (p.bio !== void 0) header.bio = p.bio;
|
|
11568
|
+
if (localized.contact.email !== void 0) header.email = localized.contact.email;
|
|
11569
|
+
if (localized.contact.formUrl !== void 0) header.formUrl = localized.contact.formUrl;
|
|
11570
|
+
const candidates = [
|
|
11571
|
+
{ kind: "experience", entries: localized.careers },
|
|
11572
|
+
{ kind: "education", entries: localized.education },
|
|
11573
|
+
{ kind: "skills", entries: localized.skills },
|
|
11574
|
+
{ kind: "certifications", entries: localized.certifications },
|
|
11575
|
+
{ kind: "publications", entries: localized.publications },
|
|
11576
|
+
{ kind: "honors", entries: localized.honors },
|
|
11577
|
+
{ kind: "courses", entries: localized.courses },
|
|
11578
|
+
{ kind: "patents", entries: localized.patents },
|
|
11579
|
+
{ kind: "languages", entries: localized.languages },
|
|
11580
|
+
{ kind: "volunteering", entries: localized.volunteering },
|
|
11581
|
+
{ kind: "memberships", entries: localized.memberships }
|
|
11582
|
+
];
|
|
11583
|
+
return {
|
|
11584
|
+
resolvedLocale: localized.resolvedLocale,
|
|
11585
|
+
header,
|
|
11586
|
+
sections: candidates.filter((section) => section.entries.length > 0)
|
|
11587
|
+
};
|
|
11588
|
+
}
|
|
11589
|
+
|
|
11590
|
+
// src/mcp.ts
|
|
11591
|
+
var MCP_PROFILE_SECTIONS = [
|
|
11592
|
+
"profile",
|
|
11593
|
+
"links",
|
|
11594
|
+
"careers",
|
|
11595
|
+
"projects",
|
|
11596
|
+
"skills",
|
|
11597
|
+
"certifications",
|
|
11598
|
+
"memberships",
|
|
11599
|
+
"volunteering",
|
|
11600
|
+
"honors",
|
|
11601
|
+
"education",
|
|
11602
|
+
"publications",
|
|
11603
|
+
"languages",
|
|
11604
|
+
"courses",
|
|
11605
|
+
"patents",
|
|
11606
|
+
"testScores",
|
|
11607
|
+
"recommendations",
|
|
11608
|
+
"contact"
|
|
11609
|
+
];
|
|
11610
|
+
var McpRequestError = class extends Error {
|
|
11611
|
+
constructor(message, options) {
|
|
11612
|
+
super(message, options);
|
|
11613
|
+
this.name = "McpRequestError";
|
|
11614
|
+
}
|
|
11615
|
+
};
|
|
11616
|
+
var LANG_PROPERTY = {
|
|
11617
|
+
type: "string",
|
|
11618
|
+
description: 'BCP-47 locale tag (e.g. "ja", "en"). Resolves to the requested locale, falling back to the profile default when omitted or unavailable.'
|
|
11619
|
+
};
|
|
11620
|
+
var MCP_TOOLS = [
|
|
11621
|
+
{
|
|
11622
|
+
name: "get_profile",
|
|
11623
|
+
title: "Get profile",
|
|
11624
|
+
description: "Return the owner's full public profile, resolved to one locale and privacy-filtered (identical to the public `GET /api/profile`).",
|
|
11625
|
+
inputSchema: {
|
|
11626
|
+
type: "object",
|
|
11627
|
+
properties: { lang: LANG_PROPERTY },
|
|
11628
|
+
additionalProperties: false
|
|
11629
|
+
}
|
|
11630
|
+
},
|
|
11631
|
+
{
|
|
11632
|
+
name: "get_section",
|
|
11633
|
+
title: "Get profile section",
|
|
11634
|
+
description: "Return a single section of the public profile (e.g. careers, education, skills), resolved to one locale and privacy-filtered.",
|
|
11635
|
+
inputSchema: {
|
|
11636
|
+
type: "object",
|
|
11637
|
+
properties: {
|
|
11638
|
+
section: {
|
|
11639
|
+
type: "string",
|
|
11640
|
+
enum: [...MCP_PROFILE_SECTIONS],
|
|
11641
|
+
description: "Which profile section to return."
|
|
11642
|
+
},
|
|
11643
|
+
lang: LANG_PROPERTY
|
|
11644
|
+
},
|
|
11645
|
+
required: ["section"],
|
|
11646
|
+
additionalProperties: false
|
|
11647
|
+
}
|
|
11648
|
+
},
|
|
11649
|
+
{
|
|
11650
|
+
name: "get_jsonld",
|
|
11651
|
+
title: "Get JSON-LD",
|
|
11652
|
+
description: "Return the Schema.org JSON-LD (a `ProfilePage` wrapping a `Person`) for the profile, resolved to one locale (identical to `GET /api/jsonld`).",
|
|
11653
|
+
inputSchema: {
|
|
11654
|
+
type: "object",
|
|
11655
|
+
properties: { lang: LANG_PROPERTY },
|
|
11656
|
+
additionalProperties: false
|
|
11657
|
+
}
|
|
11658
|
+
},
|
|
11659
|
+
{
|
|
11660
|
+
name: "list_locales",
|
|
11661
|
+
title: "List locales",
|
|
11662
|
+
description: "List the locales this profile is available in, plus the default \u2014 useful before calling another tool with a `lang` argument.",
|
|
11663
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
11664
|
+
}
|
|
11665
|
+
];
|
|
11666
|
+
var MCP_RESOURCES = [
|
|
11667
|
+
{
|
|
11668
|
+
uri: "takuhon://profile",
|
|
11669
|
+
name: "profile",
|
|
11670
|
+
title: "Canonical profile (takuhon.json)",
|
|
11671
|
+
description: "The full canonical takuhon.json, privacy-filtered, with every locale retained (identical to `GET /takuhon.json`).",
|
|
11672
|
+
mimeType: "application/json"
|
|
11673
|
+
},
|
|
11674
|
+
{
|
|
11675
|
+
uri: "takuhon://schema",
|
|
11676
|
+
name: "schema",
|
|
11677
|
+
title: "Takuhon JSON Schema",
|
|
11678
|
+
description: "The public JSON Schema contract the profile conforms to (identical to `GET /api/schema`). Lets an agent understand the document shape.",
|
|
11679
|
+
mimeType: "application/json"
|
|
11680
|
+
}
|
|
11681
|
+
];
|
|
11682
|
+
function executeMcpTool(name, args, profile) {
|
|
11683
|
+
switch (name) {
|
|
11684
|
+
case "get_profile": {
|
|
11685
|
+
const localized = publicView(profile, readLang(args));
|
|
11686
|
+
return { data: localized, resolvedLocale: localized.resolvedLocale };
|
|
11687
|
+
}
|
|
11688
|
+
case "get_section": {
|
|
11689
|
+
const section = readSection(args);
|
|
11690
|
+
const localized = publicView(profile, readLang(args));
|
|
11691
|
+
return { data: localized[section], resolvedLocale: localized.resolvedLocale };
|
|
11692
|
+
}
|
|
11693
|
+
case "get_jsonld": {
|
|
11694
|
+
const localized = publicView(profile, readLang(args));
|
|
11695
|
+
return { data: generateJsonLd(localized), resolvedLocale: localized.resolvedLocale };
|
|
11696
|
+
}
|
|
11697
|
+
case "list_locales":
|
|
11698
|
+
return {
|
|
11699
|
+
data: {
|
|
11700
|
+
defaultLocale: profile.settings.defaultLocale,
|
|
11701
|
+
availableLocales: profile.settings.availableLocales,
|
|
11702
|
+
...profile.settings.fallbackLocale !== void 0 ? { fallbackLocale: profile.settings.fallbackLocale } : {}
|
|
11703
|
+
}
|
|
11704
|
+
};
|
|
11705
|
+
default:
|
|
11706
|
+
throw new McpRequestError(`Unknown MCP tool: ${name}`);
|
|
11707
|
+
}
|
|
11708
|
+
}
|
|
11709
|
+
function readMcpResource(uri, profile) {
|
|
11710
|
+
switch (uri) {
|
|
11711
|
+
case "takuhon://profile":
|
|
11712
|
+
return {
|
|
11713
|
+
uri,
|
|
11714
|
+
mimeType: "application/json",
|
|
11715
|
+
data: applyPublicPrivacyFilter(profile)
|
|
11716
|
+
};
|
|
11717
|
+
case "takuhon://schema":
|
|
11718
|
+
return { uri, mimeType: "application/json", data: schema };
|
|
11719
|
+
default:
|
|
11720
|
+
throw new McpRequestError(`Unknown MCP resource: ${uri}`);
|
|
11721
|
+
}
|
|
11722
|
+
}
|
|
11723
|
+
function publicView(profile, lang) {
|
|
11724
|
+
return applyPublicPrivacyFilter(resolveLocale(normalize(profile), lang));
|
|
11725
|
+
}
|
|
11726
|
+
function readLang(args) {
|
|
11727
|
+
const lang = args.lang;
|
|
11728
|
+
if (lang === void 0) return void 0;
|
|
11729
|
+
if (typeof lang !== "string") {
|
|
11730
|
+
throw new McpRequestError("`lang` must be a string (a BCP-47 locale tag).");
|
|
11731
|
+
}
|
|
11732
|
+
return lang;
|
|
11733
|
+
}
|
|
11734
|
+
function readSection(args) {
|
|
11735
|
+
const section = args.section;
|
|
11736
|
+
if (typeof section !== "string" || !isProfileSection(section)) {
|
|
11737
|
+
throw new McpRequestError(`\`section\` must be one of: ${MCP_PROFILE_SECTIONS.join(", ")}.`);
|
|
11738
|
+
}
|
|
11739
|
+
return section;
|
|
11740
|
+
}
|
|
11741
|
+
function isProfileSection(value) {
|
|
11742
|
+
return MCP_PROFILE_SECTIONS.includes(value);
|
|
11743
|
+
}
|
|
11744
|
+
|
|
11561
11745
|
// src/image.ts
|
|
11562
11746
|
var ACCEPTED_IMAGE_MIME_TYPES = [
|
|
11563
11747
|
"image/jpeg",
|
|
@@ -11898,6 +12082,10 @@ export {
|
|
|
11898
12082
|
MAX_IMAGE_BYTES,
|
|
11899
12083
|
MAX_IMAGE_DIMENSION,
|
|
11900
12084
|
MAX_IMAGE_FRAMES,
|
|
12085
|
+
MCP_PROFILE_SECTIONS,
|
|
12086
|
+
MCP_RESOURCES,
|
|
12087
|
+
MCP_TOOLS,
|
|
12088
|
+
McpRequestError,
|
|
11901
12089
|
MigrationError,
|
|
11902
12090
|
NotFoundError,
|
|
11903
12091
|
RANK_FULL_CODING_HOURS,
|
|
@@ -11908,8 +12096,10 @@ export {
|
|
|
11908
12096
|
StorageError,
|
|
11909
12097
|
applyPublicPrivacyFilter,
|
|
11910
12098
|
computeLanguagePercentages,
|
|
12099
|
+
deriveCv,
|
|
11911
12100
|
deriveRankTier,
|
|
11912
12101
|
detectImageMime,
|
|
12102
|
+
executeMcpTool,
|
|
11913
12103
|
exportTakuhon,
|
|
11914
12104
|
formatCodingTime,
|
|
11915
12105
|
generateJsonLd,
|
|
@@ -11921,6 +12111,7 @@ export {
|
|
|
11921
12111
|
migrations,
|
|
11922
12112
|
normalize,
|
|
11923
12113
|
readImageInfo,
|
|
12114
|
+
readMcpResource,
|
|
11924
12115
|
renderActivitySvg,
|
|
11925
12116
|
resolveLocale,
|
|
11926
12117
|
schema,
|