release: 0.1.0-alpha.1 - #149
Conversation
…onfig.json This allows sdks to be built using tsgo - see microsoft/typescript-go#474
…kage‘s public interface
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Release version 0.1.0-alpha.1 and add generated Terminal49 TypeScript SDK resources with MCP server tools and CI workflowIntroduce the initial SDK and MCP server: generated API client and resource modules, MCP tool handlers for core endpoints, server CLI and transports, build/test/release tooling, and CI. Key entrypoints include 📍Where to StartStart with the SDK client initialization and resource wiring in src/client.ts, then review the MCP server entrypoint and tool registration in packages/mcp-server/src/index.ts and packages/mcp-server/src/tools/index.ts. 📊 Macroscope summarized a350415. 50 files reviewed, 63 issues evaluated, 45 issues filtered, 11 comments posted. View details |
| result[key] = firstVariant[key]; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
removeAnyOf drops anyOf even when the first variant is a primitive or null, leaving the rest of the schema unchanged. This broadens accepted inputs or yields an invalid schema, and contradicts the intent to "use only the first variant" because no replacement is applied for non-object variants.
Consider returning the first variant when it isn’t an object, so the function actually uses the first anyOf member in all cases before continuing recursion.
- }
-
- delete result.anyOf;
+ } else {
+ return removeAnyOf(firstVariant as JSONSchema);
+ }
+ delete result.anyOf;🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| [ "$(basename "$(dirname "$PWD")")" = 'tmp' ] || | ||
| # The name of the containing directory that 'yarn` uses, which looks like | ||
| # $(yarn cache dir)/.tmp/XXXXX | ||
| [ "$(basename "$(dirname "$PWD")")" = '.tmp' ] |
There was a problem hiding this comment.
Both the npm cache check (file:scripts/utils/check-is-in-git-install.sh:6) and the yarn cache check (file:scripts/utils/check-is-in-git-install.sh:9) in scripts/utils/check-is-in-git-install.sh currently compare the parent of PWD, but npm’s git clones and yarn’s cache layout place the tmp/.tmp directory one level higher. Update both checks to inspect the grandparent directory name (basename $(dirname $(dirname "$PWD"))) against tmp (npm) or .tmp (yarn) to accurately detect cache-based installations.
-[ "$(basename "$(dirname "$PWD")")" = '.tmp' ]
+[ "$(basename "$(dirname "$(dirname "$PWD")")")" = '.tmp' ]🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| return result; | ||
| } | ||
|
|
||
| for (const key in result) { |
There was a problem hiding this comment.
When a circular $ref causes a property to be deleted under properties, the parent schema’s required (and potentially dependentRequired) is not updated. This yields schemas that require properties that no longer exist, leading to invalid or contradictory validation.
Consider adjusting inlineRefsRecursive to special-case properties: when a property is removed due to a circular ref, also remove its name from required and, if present, clean up related entries in dependentRequired for that property. This keeps the resulting schema consistent and valid.
- for (const key in result) {
- if (result[key] && typeof result[key] === 'object') {
- const processed = inlineRefsRecursive(result[key] as JSONSchema, defs, refPath);
- if (processed === null) {
- // Remove properties that would cause circular references
- delete result[key];
- } else {
- result[key] = processed;
- }
- }
- }
+ if (result.properties && typeof result.properties === 'object') {
+ const props = { ...(result.properties as Record<string, JSONSchema>) };
+ for (const propName in props) {
+ const processedProp = inlineRefsRecursive(props[propName] as JSONSchema, defs, refPath);
+ if (processedProp === null) {
+ delete props[propName];
+ if (Array.isArray(result.required)) {
+ result.required = (result.required as string[]).filter((r) => r !== propName);
+ }
+ if (result.dependentRequired && typeof result.dependentRequired === 'object') {
+ delete (result.dependentRequired as Record<string, string[]>)[propName];
+ // Optionally, also remove references to `propName` inside arrays of other dependencies if present.
+ // for (const dep in result.dependentRequired as Record<string, string[]>) {
+ // (result.dependentRequired as Record<string, string[]>)[dep] = (result.dependentRequired as Record<string, string[]>)[dep].filter((r) => r !== propName);
+ // }
+ }
+ } else {
+ props[propName] = processedProp;
+ }
+ }
+ result.properties = props;
+ }
+
+ for (const key in result) {
+ if (key === 'properties') continue;
+ if (result[key] && typeof result[key] === 'object') {
+ const processed = inlineRefsRecursive(result[key] as JSONSchema, defs, refPath);
+ if (processed === null) {
+ // Remove properties that would cause circular references
+ delete result[key];
+ } else {
+ result[key] = processed;
+ }
+ }
+ }🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| postPath = true; | ||
| } | ||
| const value = params[index]; | ||
| let encoded = (postPath ? encodeURIComponent : pathEncoder)('' + value); |
There was a problem hiding this comment.
Coercing params with '' + value will throw a TypeError when value is a Symbol, causing the tag function to crash before it can raise a Terminal49Error. This affects both the initial encoding and the invalid-parameter branch.
Consider using String(value) for coercion in both places. This safely handles Symbol (and other primitives) and preserves the intended behavior of emitting a controlled Terminal49Error for invalid segments.
- let encoded = (postPath ? encodeURIComponent : pathEncoder)('' + value);
+ let encoded = (postPath ? encodeURIComponent : pathEncoder)(String(value));
- encoded = value + '';
+ encoded = String(value);🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| { | ||
| patterns: [ | ||
| { | ||
| regex: '^terminal49(/.*)?', |
There was a problem hiding this comment.
no-restricted-imports uses an unsupported regex property inside patterns, which doesn’t match the rule schema. This can cause a runtime config error or the rule to be ignored.
Consider switching to the supported object form with group: ['^terminal49(/.*)?'] and keep the message to enforce the restriction as intended.
- regex: '^terminal49(/.*)?',
+ group: ['^terminal49(/.*)?'],🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| variantSchema['description'] = tool.description; | ||
| } | ||
|
|
||
| const usedDefs = findUsedDefs(variant, defs); |
There was a problem hiding this comment.
removeTopLevelUnions computes $defs using findUsedDefs(variant, defs), but the final variantSchema is a merge of inputSchema and variant. $refs from inputSchema won’t be discovered and can be omitted, leaving variantSchema with $refs pointing to missing definitions.
Consider computing used defs from the fully merged variantSchema (instead of just the variant) before assigning $defs so all referenced definitions are included.
- const usedDefs = findUsedDefs(variant, defs);
+ const usedDefs = findUsedDefs(variantSchema, defs);🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| return values.flatMap((v) => v.split(',')); | ||
| }, | ||
| }) | ||
| .option('no-capability', { |
There was a problem hiding this comment.
--no-capability uses choices: CAPABILITY_CHOICES while also trying to support comma-separated values via coerce. Yargs validates choices before coerce, so inputs like --no-capability=refs,formats are rejected as the raw string "refs,formats" is not in CAPABILITY_CHOICES.
Consider removing choices from --no-capability and validating after splitting (e.g., mirroring the --capability path), so comma-separated values work as intended.
- .option('no-capability', {
- type: 'string',
- array: true,
- description: 'Unset client capabilities',
- choices: CAPABILITY_CHOICES,
- coerce: (values: string[]) => {
- return values.flatMap((v) => v.split(','));
- },
- })
+ .option('no-capability', {
+ type: 'string',
+ array: true,
+ description: 'Unset client capabilities',
+ coerce: (values: string[]) => {
+ return values.flatMap((v) => v.split(','));
+ },
+ })🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
|
|
||
| const renameMap = new Map<string, string>(); | ||
| const usedNames = new Set<string>(); | ||
|
|
There was a problem hiding this comment.
Consider initializing usedNames in truncateToolNames (in applyCompatibilityTransformations) with all existing tool names before generating truncated or suffixed names, so that both the non-collide truncation path (truncateToolNames) and the suffix-based collision loop (truncateToolNames) avoid creating duplicates with original names.
+ // Track existing names (those not exceeding maxLength) to avoid collisions with originals
+ for (const name of names) {
+ if (name.length <= maxLength) {
+ usedNames.add(name);
+ }
+ }
- if (!willCollide) {
- for (const name of toTruncate) {
- const truncatedName = name.slice(0, maxLength);
- renameMap.set(name, truncatedName);
- }
+ if (!willCollide) {
+ for (const name of toTruncate) {
+ const truncatedName = name.slice(0, maxLength);
+ if (usedNames.has(truncatedName)) {
+ const baseName = name.slice(0, maxLength - 1);
+ let counter = 1;
+ while (usedNames.has(baseName + counter)) {
+ counter++;
+ }
+ const finalName = baseName + counter;
+ renameMap.set(name, finalName);
+ usedNames.add(finalName);
+ } else {
+ renameMap.set(name, truncatedName);
+ usedNames.add(truncatedName);
+ }
+ }
} else {
const baseLength = maxLength - 1;
for (const name of toTruncate) {
const baseName = name.slice(0, baseLength);
let counter = 1;
while (usedNames.has(baseName + counter)) {
counter++;
}
const finalName = baseName + counter;
renameMap.set(name, finalName);
usedNames.add(finalName);
}
}🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
| const baseLength = maxLength - 1; | ||
|
|
||
| for (const name of toTruncate) { | ||
| const baseName = name.slice(0, baseLength); |
There was a problem hiding this comment.
Numeric suffixes can push finalName over maxLength in the collision path. When counter >= 10, baseName.length remains maxLength - 1, so baseName + counter exceeds the limit.
Consider computing the suffix length first and truncating the base accordingly (e.g., derive allowedBaseLength = maxLength - String(counter).length) inside the uniqueness loop so the final name never exceeds maxLength.
- const baseName = name.slice(0, baseLength);
- let counter = 1;
-
- while (usedNames.has(baseName + counter)) {
- counter++;
- }
-
- const finalName = baseName + counter;
+ let counter = 1;
+ let finalName = "";
+ while (true) {
+ const suffix = String(counter);
+ const allowedBaseLength = Math.max(0, maxLength - suffix.length);
+ const baseName = name.slice(0, allowedBaseLength);
+ finalName = baseName + suffix;
+ if (!usedNames.has(finalName)) {
+ break;
+ }
+ counter++;
+ }🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
|
|
||
| async function postprocess() { | ||
| for await (const file of walk(distDir)) { | ||
| if (!/(\.d)?[cm]?ts$/.test(file)) continue; |
There was a problem hiding this comment.
The file filter regex /(\.d)?[cm]?ts$/ doesn’t match *.d.mts or *.d.cts because it expects .d directly before mts/cts with no dot. This means .d.mts and .d.cts files are skipped and their /// <reference ...> lines aren’t stripped.
Consider updating the pattern to allow an extra dot after .d, e.g., /(?:\.d\.)?[cm]?ts$/, so .ts, .cts, .mts, .d.ts, .d.cts, and .d.mts are all covered consistently.
- if (!/(\.d)?[cm]?ts$/.test(file)) continue;
+ if (!/(?:\.d\.)?[cm]?ts$/.test(file)) continue;🚀 Reply to ask Macroscope to explain or update this suggestion.
👍 Helpful? React to give us feedback.
|
🧪 Testing |
a350415 to
19b0c56
Compare
19b0c56 to
491dde8
Compare
491dde8 to
a65ff68
Compare
a65ff68 to
742c8d3
Compare
742c8d3 to
adc7c47
Compare
21f6a0f to
5cf111f
Compare
5cf111f to
366f934
Compare
366f934 to
9b8108d
Compare
9b8108d to
446da42
Compare
446da42 to
e663b58
Compare
e663b58 to
b96186f
Compare
Automated Release PR
0.1.0-alpha.1 (2025-11-13)
Full Changelog: v0.0.1-alpha.0...v0.1.0-alpha.1
Features
Bug Fixes
Performance Improvements
Chores
compilerOptions.baseUrlfrom tsconfig.json (2dc6c24)docs_searchtool at other URLs (7203f41)Documentation
Refactors
This pull request is managed by Stainless's GitHub App.
The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.
For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.
🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions