@girardmedia/bootspring 3.0.0 → 3.1.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/cli/index.js +244 -53
- package/dist/core/index.d.ts +1 -1
- package/dist/core.js +10 -8
- package/dist/mcp-server.js +322 -61
- package/package.json +1 -1
- package/scripts/postinstall.cjs +7 -1
package/dist/cli/index.js
CHANGED
|
@@ -33,9 +33,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
));
|
|
34
34
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
35
35
|
|
|
36
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
36
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js
|
|
37
37
|
var init_cjs_shims = __esm({
|
|
38
|
-
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
38
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js"() {
|
|
39
39
|
"use strict";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
@@ -3386,7 +3386,7 @@ var init_release = __esm({
|
|
|
3386
3386
|
"../../packages/shared/src/release.ts"() {
|
|
3387
3387
|
"use strict";
|
|
3388
3388
|
init_cjs_shims();
|
|
3389
|
-
BOOTSPRING_VERSION = "3.
|
|
3389
|
+
BOOTSPRING_VERSION = "3.1.0";
|
|
3390
3390
|
BOOTSPRING_PACKAGE_NAME = "@girardmedia/bootspring";
|
|
3391
3391
|
}
|
|
3392
3392
|
});
|
|
@@ -32899,13 +32899,16 @@ var require_data = __commonJS({
|
|
|
32899
32899
|
}
|
|
32900
32900
|
});
|
|
32901
32901
|
|
|
32902
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
32902
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js
|
|
32903
32903
|
var require_utils = __commonJS({
|
|
32904
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
32904
|
+
"../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js"(exports2, module2) {
|
|
32905
32905
|
"use strict";
|
|
32906
32906
|
init_cjs_shims();
|
|
32907
32907
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
32908
32908
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
32909
|
+
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
32910
|
+
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
32911
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
|
|
32909
32912
|
function stringArrayToHexStripped(input) {
|
|
32910
32913
|
let acc = "";
|
|
32911
32914
|
let code = 0;
|
|
@@ -33098,27 +33101,77 @@ var require_utils = __commonJS({
|
|
|
33098
33101
|
}
|
|
33099
33102
|
return output.join("");
|
|
33100
33103
|
}
|
|
33101
|
-
|
|
33102
|
-
|
|
33103
|
-
|
|
33104
|
-
|
|
33105
|
-
|
|
33106
|
-
|
|
33107
|
-
|
|
33108
|
-
|
|
33109
|
-
|
|
33110
|
-
|
|
33104
|
+
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
33105
|
+
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
33106
|
+
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
33107
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
33108
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
33109
|
+
re.lastIndex = 0;
|
|
33110
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
33111
|
+
}
|
|
33112
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
33113
|
+
if (input.indexOf("%") === -1) {
|
|
33114
|
+
return input;
|
|
33111
33115
|
}
|
|
33112
|
-
|
|
33113
|
-
|
|
33116
|
+
let output = "";
|
|
33117
|
+
for (let i = 0; i < input.length; i++) {
|
|
33118
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
33119
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
33120
|
+
if (isHexPair(hex3)) {
|
|
33121
|
+
const normalizedHex = hex3.toUpperCase();
|
|
33122
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
33123
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
33124
|
+
output += decoded;
|
|
33125
|
+
} else {
|
|
33126
|
+
output += "%" + normalizedHex;
|
|
33127
|
+
}
|
|
33128
|
+
i += 2;
|
|
33129
|
+
continue;
|
|
33130
|
+
}
|
|
33131
|
+
}
|
|
33132
|
+
output += input[i];
|
|
33114
33133
|
}
|
|
33115
|
-
|
|
33116
|
-
|
|
33134
|
+
return output;
|
|
33135
|
+
}
|
|
33136
|
+
function normalizePathEncoding(input) {
|
|
33137
|
+
let output = "";
|
|
33138
|
+
for (let i = 0; i < input.length; i++) {
|
|
33139
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
33140
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
33141
|
+
if (isHexPair(hex3)) {
|
|
33142
|
+
const normalizedHex = hex3.toUpperCase();
|
|
33143
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
33144
|
+
if (decoded !== "." && isUnreserved(decoded)) {
|
|
33145
|
+
output += decoded;
|
|
33146
|
+
} else {
|
|
33147
|
+
output += "%" + normalizedHex;
|
|
33148
|
+
}
|
|
33149
|
+
i += 2;
|
|
33150
|
+
continue;
|
|
33151
|
+
}
|
|
33152
|
+
}
|
|
33153
|
+
if (isPathCharacter(input[i])) {
|
|
33154
|
+
output += input[i];
|
|
33155
|
+
} else {
|
|
33156
|
+
output += escape(input[i]);
|
|
33157
|
+
}
|
|
33117
33158
|
}
|
|
33118
|
-
|
|
33119
|
-
|
|
33159
|
+
return output;
|
|
33160
|
+
}
|
|
33161
|
+
function escapePreservingEscapes(input) {
|
|
33162
|
+
let output = "";
|
|
33163
|
+
for (let i = 0; i < input.length; i++) {
|
|
33164
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
33165
|
+
const hex3 = input.slice(i + 1, i + 3);
|
|
33166
|
+
if (isHexPair(hex3)) {
|
|
33167
|
+
output += "%" + hex3.toUpperCase();
|
|
33168
|
+
i += 2;
|
|
33169
|
+
continue;
|
|
33170
|
+
}
|
|
33171
|
+
}
|
|
33172
|
+
output += escape(input[i]);
|
|
33120
33173
|
}
|
|
33121
|
-
return
|
|
33174
|
+
return output;
|
|
33122
33175
|
}
|
|
33123
33176
|
function recomposeAuthority(component) {
|
|
33124
33177
|
const uriTokens = [];
|
|
@@ -33133,7 +33186,7 @@ var require_utils = __commonJS({
|
|
|
33133
33186
|
if (ipV6res.isIPV6 === true) {
|
|
33134
33187
|
host = `[${ipV6res.escapedHost}]`;
|
|
33135
33188
|
} else {
|
|
33136
|
-
host =
|
|
33189
|
+
host = reescapeHostDelimiters(host, false);
|
|
33137
33190
|
}
|
|
33138
33191
|
}
|
|
33139
33192
|
uriTokens.push(host);
|
|
@@ -33147,7 +33200,10 @@ var require_utils = __commonJS({
|
|
|
33147
33200
|
module2.exports = {
|
|
33148
33201
|
nonSimpleDomain,
|
|
33149
33202
|
recomposeAuthority,
|
|
33150
|
-
|
|
33203
|
+
reescapeHostDelimiters,
|
|
33204
|
+
normalizePercentEncoding,
|
|
33205
|
+
normalizePathEncoding,
|
|
33206
|
+
escapePreservingEscapes,
|
|
33151
33207
|
removeDotSegments,
|
|
33152
33208
|
isIPv4,
|
|
33153
33209
|
isUUID,
|
|
@@ -33157,9 +33213,9 @@ var require_utils = __commonJS({
|
|
|
33157
33213
|
}
|
|
33158
33214
|
});
|
|
33159
33215
|
|
|
33160
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
33216
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js
|
|
33161
33217
|
var require_schemes = __commonJS({
|
|
33162
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
33218
|
+
"../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js"(exports2, module2) {
|
|
33163
33219
|
"use strict";
|
|
33164
33220
|
init_cjs_shims();
|
|
33165
33221
|
var { isUUID } = require_utils();
|
|
@@ -33368,17 +33424,17 @@ var require_schemes = __commonJS({
|
|
|
33368
33424
|
}
|
|
33369
33425
|
});
|
|
33370
33426
|
|
|
33371
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
33427
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js
|
|
33372
33428
|
var require_fast_uri = __commonJS({
|
|
33373
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
33429
|
+
"../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js"(exports2, module2) {
|
|
33374
33430
|
"use strict";
|
|
33375
33431
|
init_cjs_shims();
|
|
33376
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
33432
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
33377
33433
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
33378
33434
|
function normalize2(uri, options) {
|
|
33379
33435
|
if (typeof uri === "string") {
|
|
33380
33436
|
uri = /** @type {T} */
|
|
33381
|
-
|
|
33437
|
+
normalizeString(uri, options);
|
|
33382
33438
|
} else if (typeof uri === "object") {
|
|
33383
33439
|
uri = /** @type {T} */
|
|
33384
33440
|
parse7(serialize(uri, options), options);
|
|
@@ -33445,19 +33501,9 @@ var require_fast_uri = __commonJS({
|
|
|
33445
33501
|
return target;
|
|
33446
33502
|
}
|
|
33447
33503
|
function equal(uriA, uriB, options) {
|
|
33448
|
-
|
|
33449
|
-
|
|
33450
|
-
|
|
33451
|
-
} else if (typeof uriA === "object") {
|
|
33452
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
33453
|
-
}
|
|
33454
|
-
if (typeof uriB === "string") {
|
|
33455
|
-
uriB = unescape(uriB);
|
|
33456
|
-
uriB = serialize(normalizeComponentEncoding(parse7(uriB, options), true), { ...options, skipEscape: true });
|
|
33457
|
-
} else if (typeof uriB === "object") {
|
|
33458
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
33459
|
-
}
|
|
33460
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
33504
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
33505
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
33506
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
|
|
33461
33507
|
}
|
|
33462
33508
|
function serialize(cmpts, opts) {
|
|
33463
33509
|
const component = {
|
|
@@ -33482,12 +33528,12 @@ var require_fast_uri = __commonJS({
|
|
|
33482
33528
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
33483
33529
|
if (component.path !== void 0) {
|
|
33484
33530
|
if (!options.skipEscape) {
|
|
33485
|
-
component.path =
|
|
33531
|
+
component.path = escapePreservingEscapes(component.path);
|
|
33486
33532
|
if (component.scheme !== void 0) {
|
|
33487
33533
|
component.path = component.path.split("%3A").join(":");
|
|
33488
33534
|
}
|
|
33489
33535
|
} else {
|
|
33490
|
-
component.path =
|
|
33536
|
+
component.path = normalizePercentEncoding(component.path);
|
|
33491
33537
|
}
|
|
33492
33538
|
}
|
|
33493
33539
|
if (options.reference !== "suffix" && component.scheme) {
|
|
@@ -33522,7 +33568,16 @@ var require_fast_uri = __commonJS({
|
|
|
33522
33568
|
return uriTokens.join("");
|
|
33523
33569
|
}
|
|
33524
33570
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
33525
|
-
function
|
|
33571
|
+
function getParseError(parsed, matches) {
|
|
33572
|
+
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
33573
|
+
return 'URI path must start with "/" when authority is present.';
|
|
33574
|
+
}
|
|
33575
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
|
|
33576
|
+
return "URI port is malformed.";
|
|
33577
|
+
}
|
|
33578
|
+
return void 0;
|
|
33579
|
+
}
|
|
33580
|
+
function parseWithStatus(uri, opts) {
|
|
33526
33581
|
const options = Object.assign({}, opts);
|
|
33527
33582
|
const parsed = {
|
|
33528
33583
|
scheme: void 0,
|
|
@@ -33533,6 +33588,7 @@ var require_fast_uri = __commonJS({
|
|
|
33533
33588
|
query: void 0,
|
|
33534
33589
|
fragment: void 0
|
|
33535
33590
|
};
|
|
33591
|
+
let malformedAuthorityOrPort = false;
|
|
33536
33592
|
let isIP = false;
|
|
33537
33593
|
if (options.reference === "suffix") {
|
|
33538
33594
|
if (options.scheme) {
|
|
@@ -33553,6 +33609,11 @@ var require_fast_uri = __commonJS({
|
|
|
33553
33609
|
if (isNaN(parsed.port)) {
|
|
33554
33610
|
parsed.port = matches[5];
|
|
33555
33611
|
}
|
|
33612
|
+
const parseError = getParseError(parsed, matches);
|
|
33613
|
+
if (parseError !== void 0) {
|
|
33614
|
+
parsed.error = parsed.error || parseError;
|
|
33615
|
+
malformedAuthorityOrPort = true;
|
|
33616
|
+
}
|
|
33556
33617
|
if (parsed.host) {
|
|
33557
33618
|
const ipv4result = isIPv4(parsed.host);
|
|
33558
33619
|
if (ipv4result === false) {
|
|
@@ -33591,14 +33652,18 @@ var require_fast_uri = __commonJS({
|
|
|
33591
33652
|
parsed.scheme = unescape(parsed.scheme);
|
|
33592
33653
|
}
|
|
33593
33654
|
if (parsed.host !== void 0) {
|
|
33594
|
-
parsed.host = unescape(parsed.host);
|
|
33655
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
33595
33656
|
}
|
|
33596
33657
|
}
|
|
33597
33658
|
if (parsed.path) {
|
|
33598
|
-
parsed.path =
|
|
33659
|
+
parsed.path = normalizePathEncoding(parsed.path);
|
|
33599
33660
|
}
|
|
33600
33661
|
if (parsed.fragment) {
|
|
33601
|
-
|
|
33662
|
+
try {
|
|
33663
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
33664
|
+
} catch {
|
|
33665
|
+
parsed.error = parsed.error || "URI malformed";
|
|
33666
|
+
}
|
|
33602
33667
|
}
|
|
33603
33668
|
}
|
|
33604
33669
|
if (schemeHandler && schemeHandler.parse) {
|
|
@@ -33607,7 +33672,29 @@ var require_fast_uri = __commonJS({
|
|
|
33607
33672
|
} else {
|
|
33608
33673
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
33609
33674
|
}
|
|
33610
|
-
return parsed;
|
|
33675
|
+
return { parsed, malformedAuthorityOrPort };
|
|
33676
|
+
}
|
|
33677
|
+
function parse7(uri, opts) {
|
|
33678
|
+
return parseWithStatus(uri, opts).parsed;
|
|
33679
|
+
}
|
|
33680
|
+
function normalizeString(uri, opts) {
|
|
33681
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
33682
|
+
}
|
|
33683
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
33684
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
33685
|
+
return {
|
|
33686
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
33687
|
+
malformedAuthorityOrPort
|
|
33688
|
+
};
|
|
33689
|
+
}
|
|
33690
|
+
function normalizeComparableURI(uri, opts) {
|
|
33691
|
+
if (typeof uri === "string") {
|
|
33692
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
|
|
33693
|
+
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
33694
|
+
}
|
|
33695
|
+
if (typeof uri === "object") {
|
|
33696
|
+
return serialize(uri, opts);
|
|
33697
|
+
}
|
|
33611
33698
|
}
|
|
33612
33699
|
var fastUri = {
|
|
33613
33700
|
SCHEMES,
|
|
@@ -56944,7 +57031,7 @@ function registerBuildCommand(program3) {
|
|
|
56944
57031
|
print.info(`Complexity: ${next.complexity ?? "Unknown"}`);
|
|
56945
57032
|
if (current) print.info(`Status: ${next.status}`);
|
|
56946
57033
|
});
|
|
56947
|
-
build.command("done").alias("complete").description("Mark the current task as done
|
|
57034
|
+
build.command("done").alias("complete").description("Mark the current task as done, auto-commit, and show next task").option("--no-commit", "Skip auto-commit").action((opts) => {
|
|
56948
57035
|
const state = loadBuildStateWithAutoSync();
|
|
56949
57036
|
if (!state) {
|
|
56950
57037
|
print.error("No build state found");
|
|
@@ -56958,15 +57045,54 @@ function registerBuildCommand(program3) {
|
|
|
56958
57045
|
return;
|
|
56959
57046
|
}
|
|
56960
57047
|
const currentId = queue[idx].id;
|
|
57048
|
+
const currentTitle = queue[idx].title;
|
|
57049
|
+
if (opts.commit !== false) {
|
|
57050
|
+
try {
|
|
57051
|
+
const { execSync: execSync15 } = require("child_process");
|
|
57052
|
+
const cwd = process.cwd();
|
|
57053
|
+
const status = execSync15("git status --porcelain", { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
57054
|
+
if (status) {
|
|
57055
|
+
execSync15("git add -A", { cwd, stdio: ["ignore", "ignore", "ignore"] });
|
|
57056
|
+
const msg = `feat(${currentId}): ${currentTitle}`;
|
|
57057
|
+
execSync15(`git commit -m ${JSON.stringify(msg)}`, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
57058
|
+
print.success(`Committed: ${msg}`);
|
|
57059
|
+
}
|
|
57060
|
+
} catch {
|
|
57061
|
+
}
|
|
57062
|
+
}
|
|
56961
57063
|
queue[idx].status = "completed";
|
|
56962
57064
|
if (state.loopSession) {
|
|
56963
57065
|
state.loopSession.currentIteration = (state.loopSession.currentIteration ?? 0) + 1;
|
|
56964
57066
|
}
|
|
56965
57067
|
saveBuildState(state);
|
|
56966
|
-
const nextTask =
|
|
57068
|
+
const nextTask = (() => {
|
|
57069
|
+
for (const task of queue) {
|
|
57070
|
+
if (task.status !== "pending") continue;
|
|
57071
|
+
if (task.dependencies?.length) {
|
|
57072
|
+
const allDone = task.dependencies.every((depId) => {
|
|
57073
|
+
const dep = queue.find((t) => t.id === depId);
|
|
57074
|
+
return dep && dep.status === "completed";
|
|
57075
|
+
});
|
|
57076
|
+
if (!allDone) continue;
|
|
57077
|
+
}
|
|
57078
|
+
return task;
|
|
57079
|
+
}
|
|
57080
|
+
return null;
|
|
57081
|
+
})();
|
|
56967
57082
|
print.success(`Task ${currentId} marked as done`);
|
|
56968
57083
|
if (nextTask) {
|
|
56969
|
-
|
|
57084
|
+
console.log("");
|
|
57085
|
+
print.header("Next Task");
|
|
57086
|
+
print.info(`ID: ${nextTask.id}`);
|
|
57087
|
+
print.info(`Title: ${nextTask.title}`);
|
|
57088
|
+
if (nextTask.phase) print.info(`Phase: ${nextTask.phase}`);
|
|
57089
|
+
if (nextTask.description) print.info(`Description: ${nextTask.description}`);
|
|
57090
|
+
if (nextTask.acceptanceCriteria && nextTask.acceptanceCriteria.length > 0) {
|
|
57091
|
+
print.info("Acceptance criteria:");
|
|
57092
|
+
for (const ac of nextTask.acceptanceCriteria) {
|
|
57093
|
+
console.log(` [ ] ${ac}`);
|
|
57094
|
+
}
|
|
57095
|
+
}
|
|
56970
57096
|
} else {
|
|
56971
57097
|
print.success("No more pending tasks!");
|
|
56972
57098
|
}
|
|
@@ -57852,6 +57978,71 @@ ${supplementaryContent}
|
|
|
57852
57978
|
print.dim(`${snapshot.completedCount} completed, ${snapshot.pendingCount} pending`);
|
|
57853
57979
|
}
|
|
57854
57980
|
});
|
|
57981
|
+
build.command("handoff").description("Save or load session handoff state for cross-session continuity").option("--save", "Save current session state").option("--notes <notes>", "Notes for the next session").option("--json", "Output as JSON").action((opts) => {
|
|
57982
|
+
const handoffPath = path52.join(process.cwd(), "planning", ".handoff.json");
|
|
57983
|
+
if (opts.save) {
|
|
57984
|
+
const state = loadBuildStateWithAutoSync(true);
|
|
57985
|
+
const queue = state?.implementationQueue ?? [];
|
|
57986
|
+
const inProgress = queue.find((t) => t.status === "in_progress");
|
|
57987
|
+
const lastCompleted = [...queue].reverse().find((t) => t.status === "completed");
|
|
57988
|
+
let filesModified = [];
|
|
57989
|
+
try {
|
|
57990
|
+
const { execSync: execSync15 } = require("child_process");
|
|
57991
|
+
const gitDiff = execSync15("git diff --name-only HEAD~1 2>/dev/null || true", { encoding: "utf8" }).trim();
|
|
57992
|
+
if (gitDiff) filesModified = gitDiff.split("\n").filter(Boolean);
|
|
57993
|
+
} catch {
|
|
57994
|
+
}
|
|
57995
|
+
const handoff = {
|
|
57996
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
57997
|
+
lastTaskId: lastCompleted?.id ?? null,
|
|
57998
|
+
inProgressTask: inProgress?.id ?? null,
|
|
57999
|
+
inProgressTitle: inProgress?.title ?? null,
|
|
58000
|
+
filesModified,
|
|
58001
|
+
notes: opts.notes ?? "",
|
|
58002
|
+
blockers: [],
|
|
58003
|
+
progress: {
|
|
58004
|
+
completed: queue.filter((t) => t.status === "completed").length,
|
|
58005
|
+
pending: queue.filter((t) => t.status === "pending").length,
|
|
58006
|
+
total: queue.length
|
|
58007
|
+
}
|
|
58008
|
+
};
|
|
58009
|
+
const dir = path52.dirname(handoffPath);
|
|
58010
|
+
if (!fs51.existsSync(dir)) fs51.mkdirSync(dir, { recursive: true });
|
|
58011
|
+
fs51.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2));
|
|
58012
|
+
if (opts.json) {
|
|
58013
|
+
console.log(JSON.stringify({ saved: true, handoff }));
|
|
58014
|
+
} else {
|
|
58015
|
+
print.success("Session handoff saved");
|
|
58016
|
+
if (inProgress) print.info(`In-progress: ${inProgress.id} \u2014 ${inProgress.title}`);
|
|
58017
|
+
if (opts.notes) print.info(`Notes: ${opts.notes}`);
|
|
58018
|
+
}
|
|
58019
|
+
return;
|
|
58020
|
+
}
|
|
58021
|
+
if (!fs51.existsSync(handoffPath)) {
|
|
58022
|
+
if (opts.json) {
|
|
58023
|
+
console.log(JSON.stringify({ hasHandoff: false }));
|
|
58024
|
+
} else {
|
|
58025
|
+
print.info("No previous session handoff found.");
|
|
58026
|
+
}
|
|
58027
|
+
return;
|
|
58028
|
+
}
|
|
58029
|
+
try {
|
|
58030
|
+
const handoff = JSON.parse(fs51.readFileSync(handoffPath, "utf-8"));
|
|
58031
|
+
if (opts.json) {
|
|
58032
|
+
console.log(JSON.stringify({ hasHandoff: true, handoff }));
|
|
58033
|
+
} else {
|
|
58034
|
+
print.header("Session Handoff");
|
|
58035
|
+
print.info(`Saved: ${handoff.timestamp}`);
|
|
58036
|
+
if (handoff.inProgressTask) print.info(`In-progress: ${handoff.inProgressTask} \u2014 ${handoff.inProgressTitle ?? ""}`);
|
|
58037
|
+
if (handoff.lastTaskId) print.info(`Last completed: ${handoff.lastTaskId}`);
|
|
58038
|
+
if (handoff.notes) print.info(`Notes: ${handoff.notes}`);
|
|
58039
|
+
if (handoff.progress) print.info(`Progress: ${handoff.progress.completed}/${handoff.progress.total}`);
|
|
58040
|
+
if (handoff.filesModified?.length) print.dim(`Files: ${handoff.filesModified.slice(0, 5).join(", ")}${handoff.filesModified.length > 5 ? ` +${handoff.filesModified.length - 5} more` : ""}`);
|
|
58041
|
+
}
|
|
58042
|
+
} catch {
|
|
58043
|
+
print.error("Failed to read handoff file");
|
|
58044
|
+
}
|
|
58045
|
+
});
|
|
57855
58046
|
build.action(() => {
|
|
57856
58047
|
build.outputHelp();
|
|
57857
58048
|
});
|
package/dist/core/index.d.ts
CHANGED
|
@@ -477,7 +477,7 @@ interface InstallContext {
|
|
|
477
477
|
scriptPath: string;
|
|
478
478
|
}
|
|
479
479
|
declare const PACKAGE_NAME = "@girardmedia/bootspring";
|
|
480
|
-
declare const CURRENT_VERSION = "3.
|
|
480
|
+
declare const CURRENT_VERSION = "3.1.0";
|
|
481
481
|
declare const DEFAULT_INTERVAL_MS: number;
|
|
482
482
|
declare const STATE_PATH: string;
|
|
483
483
|
declare function compareVersions(a: string, b: string): number;
|
package/dist/core.js
CHANGED
|
@@ -33,9 +33,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
));
|
|
34
34
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
35
35
|
|
|
36
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
36
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js
|
|
37
37
|
var init_cjs_shims = __esm({
|
|
38
|
-
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
38
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js"() {
|
|
39
39
|
"use strict";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
@@ -379,7 +379,7 @@ var init_release = __esm({
|
|
|
379
379
|
"../../packages/shared/src/release.ts"() {
|
|
380
380
|
"use strict";
|
|
381
381
|
init_cjs_shims();
|
|
382
|
-
BOOTSPRING_VERSION = "3.
|
|
382
|
+
BOOTSPRING_VERSION = "3.1.0";
|
|
383
383
|
BOOTSPRING_PACKAGE_NAME = "@girardmedia/bootspring";
|
|
384
384
|
}
|
|
385
385
|
});
|
|
@@ -16603,7 +16603,7 @@ var require_dist = __commonJS({
|
|
|
16603
16603
|
));
|
|
16604
16604
|
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
16605
16605
|
var init_cjs_shims2 = __esm2({
|
|
16606
|
-
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
16606
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js"() {
|
|
16607
16607
|
"use strict";
|
|
16608
16608
|
}
|
|
16609
16609
|
});
|
|
@@ -21643,7 +21643,7 @@ ${COLORS2.dim}Run "bootspring mcp" for server options${COLORS2.reset}
|
|
|
21643
21643
|
console.log(`${COLORS2.dim}Run "bootspring mcp" for setup instructions.${COLORS2.reset}
|
|
21644
21644
|
`);
|
|
21645
21645
|
}
|
|
21646
|
-
var BOOTSPRING_VERSION2 = "3.
|
|
21646
|
+
var BOOTSPRING_VERSION2 = "3.1.0";
|
|
21647
21647
|
var BOOTSPRING_PACKAGE_NAME2 = "@girardmedia/bootspring";
|
|
21648
21648
|
var REDACTED2 = "[REDACTED]";
|
|
21649
21649
|
var SENSITIVE_KEY_PATTERN2 = /(?:^|[_-])(api[_-]?key|token|refresh[_-]?token|authorization|x[_-]?api[_-]?key|project[_-]?id)$/i;
|
|
@@ -21691,7 +21691,7 @@ var require_package = __commonJS({
|
|
|
21691
21691
|
"../../../package.json"(exports2, module2) {
|
|
21692
21692
|
module2.exports = {
|
|
21693
21693
|
name: "bootspring-workspace",
|
|
21694
|
-
version: "3.
|
|
21694
|
+
version: "3.1.0",
|
|
21695
21695
|
private: true,
|
|
21696
21696
|
description: "Workspace tooling for the Bootspring monorepo",
|
|
21697
21697
|
keywords: [
|
|
@@ -21795,8 +21795,10 @@ var require_package = __commonJS({
|
|
|
21795
21795
|
ajv: "^8.12.0"
|
|
21796
21796
|
},
|
|
21797
21797
|
minimatch: "^10.2.1",
|
|
21798
|
-
hono: "4.12.
|
|
21799
|
-
"@hono/node-server": "1.19.
|
|
21798
|
+
hono: "4.12.18",
|
|
21799
|
+
"@hono/node-server": "1.19.13",
|
|
21800
|
+
axios: ">=1.16.0",
|
|
21801
|
+
"simple-git": ">=3.36.0",
|
|
21800
21802
|
"express-rate-limit": "^8.2.2",
|
|
21801
21803
|
"path-to-regexp@<0.1.13": "0.1.13",
|
|
21802
21804
|
"path-to-regexp@>=8.0.0 <8.4.0": "8.4.0",
|
package/dist/mcp-server.js
CHANGED
|
@@ -33,9 +33,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
));
|
|
34
34
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
35
35
|
|
|
36
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
36
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js
|
|
37
37
|
var init_cjs_shims = __esm({
|
|
38
|
-
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
38
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js"() {
|
|
39
39
|
"use strict";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
@@ -26434,13 +26434,16 @@ var require_data = __commonJS({
|
|
|
26434
26434
|
}
|
|
26435
26435
|
});
|
|
26436
26436
|
|
|
26437
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
26437
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js
|
|
26438
26438
|
var require_utils = __commonJS({
|
|
26439
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
26439
|
+
"../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js"(exports2, module2) {
|
|
26440
26440
|
"use strict";
|
|
26441
26441
|
init_cjs_shims();
|
|
26442
26442
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
26443
26443
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
26444
|
+
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
26445
|
+
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
26446
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
|
|
26444
26447
|
function stringArrayToHexStripped(input) {
|
|
26445
26448
|
let acc = "";
|
|
26446
26449
|
let code = 0;
|
|
@@ -26633,27 +26636,77 @@ var require_utils = __commonJS({
|
|
|
26633
26636
|
}
|
|
26634
26637
|
return output.join("");
|
|
26635
26638
|
}
|
|
26636
|
-
|
|
26637
|
-
|
|
26638
|
-
|
|
26639
|
-
|
|
26640
|
-
|
|
26641
|
-
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
|
|
26645
|
-
|
|
26639
|
+
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
26640
|
+
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
26641
|
+
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
26642
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
26643
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
26644
|
+
re.lastIndex = 0;
|
|
26645
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
26646
|
+
}
|
|
26647
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
26648
|
+
if (input.indexOf("%") === -1) {
|
|
26649
|
+
return input;
|
|
26646
26650
|
}
|
|
26647
|
-
|
|
26648
|
-
|
|
26651
|
+
let output = "";
|
|
26652
|
+
for (let i = 0; i < input.length; i++) {
|
|
26653
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
26654
|
+
const hex = input.slice(i + 1, i + 3);
|
|
26655
|
+
if (isHexPair(hex)) {
|
|
26656
|
+
const normalizedHex = hex.toUpperCase();
|
|
26657
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
26658
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
26659
|
+
output += decoded;
|
|
26660
|
+
} else {
|
|
26661
|
+
output += "%" + normalizedHex;
|
|
26662
|
+
}
|
|
26663
|
+
i += 2;
|
|
26664
|
+
continue;
|
|
26665
|
+
}
|
|
26666
|
+
}
|
|
26667
|
+
output += input[i];
|
|
26649
26668
|
}
|
|
26650
|
-
|
|
26651
|
-
|
|
26669
|
+
return output;
|
|
26670
|
+
}
|
|
26671
|
+
function normalizePathEncoding(input) {
|
|
26672
|
+
let output = "";
|
|
26673
|
+
for (let i = 0; i < input.length; i++) {
|
|
26674
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
26675
|
+
const hex = input.slice(i + 1, i + 3);
|
|
26676
|
+
if (isHexPair(hex)) {
|
|
26677
|
+
const normalizedHex = hex.toUpperCase();
|
|
26678
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
26679
|
+
if (decoded !== "." && isUnreserved(decoded)) {
|
|
26680
|
+
output += decoded;
|
|
26681
|
+
} else {
|
|
26682
|
+
output += "%" + normalizedHex;
|
|
26683
|
+
}
|
|
26684
|
+
i += 2;
|
|
26685
|
+
continue;
|
|
26686
|
+
}
|
|
26687
|
+
}
|
|
26688
|
+
if (isPathCharacter(input[i])) {
|
|
26689
|
+
output += input[i];
|
|
26690
|
+
} else {
|
|
26691
|
+
output += escape(input[i]);
|
|
26692
|
+
}
|
|
26652
26693
|
}
|
|
26653
|
-
|
|
26654
|
-
|
|
26694
|
+
return output;
|
|
26695
|
+
}
|
|
26696
|
+
function escapePreservingEscapes(input) {
|
|
26697
|
+
let output = "";
|
|
26698
|
+
for (let i = 0; i < input.length; i++) {
|
|
26699
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
26700
|
+
const hex = input.slice(i + 1, i + 3);
|
|
26701
|
+
if (isHexPair(hex)) {
|
|
26702
|
+
output += "%" + hex.toUpperCase();
|
|
26703
|
+
i += 2;
|
|
26704
|
+
continue;
|
|
26705
|
+
}
|
|
26706
|
+
}
|
|
26707
|
+
output += escape(input[i]);
|
|
26655
26708
|
}
|
|
26656
|
-
return
|
|
26709
|
+
return output;
|
|
26657
26710
|
}
|
|
26658
26711
|
function recomposeAuthority(component) {
|
|
26659
26712
|
const uriTokens = [];
|
|
@@ -26668,7 +26721,7 @@ var require_utils = __commonJS({
|
|
|
26668
26721
|
if (ipV6res.isIPV6 === true) {
|
|
26669
26722
|
host = `[${ipV6res.escapedHost}]`;
|
|
26670
26723
|
} else {
|
|
26671
|
-
host =
|
|
26724
|
+
host = reescapeHostDelimiters(host, false);
|
|
26672
26725
|
}
|
|
26673
26726
|
}
|
|
26674
26727
|
uriTokens.push(host);
|
|
@@ -26682,7 +26735,10 @@ var require_utils = __commonJS({
|
|
|
26682
26735
|
module2.exports = {
|
|
26683
26736
|
nonSimpleDomain,
|
|
26684
26737
|
recomposeAuthority,
|
|
26685
|
-
|
|
26738
|
+
reescapeHostDelimiters,
|
|
26739
|
+
normalizePercentEncoding,
|
|
26740
|
+
normalizePathEncoding,
|
|
26741
|
+
escapePreservingEscapes,
|
|
26686
26742
|
removeDotSegments,
|
|
26687
26743
|
isIPv4,
|
|
26688
26744
|
isUUID,
|
|
@@ -26692,9 +26748,9 @@ var require_utils = __commonJS({
|
|
|
26692
26748
|
}
|
|
26693
26749
|
});
|
|
26694
26750
|
|
|
26695
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
26751
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js
|
|
26696
26752
|
var require_schemes = __commonJS({
|
|
26697
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
26753
|
+
"../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js"(exports2, module2) {
|
|
26698
26754
|
"use strict";
|
|
26699
26755
|
init_cjs_shims();
|
|
26700
26756
|
var { isUUID } = require_utils();
|
|
@@ -26903,17 +26959,17 @@ var require_schemes = __commonJS({
|
|
|
26903
26959
|
}
|
|
26904
26960
|
});
|
|
26905
26961
|
|
|
26906
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
26962
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js
|
|
26907
26963
|
var require_fast_uri = __commonJS({
|
|
26908
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
26964
|
+
"../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js"(exports2, module2) {
|
|
26909
26965
|
"use strict";
|
|
26910
26966
|
init_cjs_shims();
|
|
26911
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
26967
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
26912
26968
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
26913
26969
|
function normalize(uri, options) {
|
|
26914
26970
|
if (typeof uri === "string") {
|
|
26915
26971
|
uri = /** @type {T} */
|
|
26916
|
-
|
|
26972
|
+
normalizeString(uri, options);
|
|
26917
26973
|
} else if (typeof uri === "object") {
|
|
26918
26974
|
uri = /** @type {T} */
|
|
26919
26975
|
parse(serialize(uri, options), options);
|
|
@@ -26980,19 +27036,9 @@ var require_fast_uri = __commonJS({
|
|
|
26980
27036
|
return target;
|
|
26981
27037
|
}
|
|
26982
27038
|
function equal(uriA, uriB, options) {
|
|
26983
|
-
|
|
26984
|
-
|
|
26985
|
-
|
|
26986
|
-
} else if (typeof uriA === "object") {
|
|
26987
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
26988
|
-
}
|
|
26989
|
-
if (typeof uriB === "string") {
|
|
26990
|
-
uriB = unescape(uriB);
|
|
26991
|
-
uriB = serialize(normalizeComponentEncoding(parse(uriB, options), true), { ...options, skipEscape: true });
|
|
26992
|
-
} else if (typeof uriB === "object") {
|
|
26993
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
26994
|
-
}
|
|
26995
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
27039
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
27040
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
27041
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
|
|
26996
27042
|
}
|
|
26997
27043
|
function serialize(cmpts, opts) {
|
|
26998
27044
|
const component = {
|
|
@@ -27017,12 +27063,12 @@ var require_fast_uri = __commonJS({
|
|
|
27017
27063
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
27018
27064
|
if (component.path !== void 0) {
|
|
27019
27065
|
if (!options.skipEscape) {
|
|
27020
|
-
component.path =
|
|
27066
|
+
component.path = escapePreservingEscapes(component.path);
|
|
27021
27067
|
if (component.scheme !== void 0) {
|
|
27022
27068
|
component.path = component.path.split("%3A").join(":");
|
|
27023
27069
|
}
|
|
27024
27070
|
} else {
|
|
27025
|
-
component.path =
|
|
27071
|
+
component.path = normalizePercentEncoding(component.path);
|
|
27026
27072
|
}
|
|
27027
27073
|
}
|
|
27028
27074
|
if (options.reference !== "suffix" && component.scheme) {
|
|
@@ -27057,7 +27103,16 @@ var require_fast_uri = __commonJS({
|
|
|
27057
27103
|
return uriTokens.join("");
|
|
27058
27104
|
}
|
|
27059
27105
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
27060
|
-
function
|
|
27106
|
+
function getParseError(parsed, matches) {
|
|
27107
|
+
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
27108
|
+
return 'URI path must start with "/" when authority is present.';
|
|
27109
|
+
}
|
|
27110
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
|
|
27111
|
+
return "URI port is malformed.";
|
|
27112
|
+
}
|
|
27113
|
+
return void 0;
|
|
27114
|
+
}
|
|
27115
|
+
function parseWithStatus(uri, opts) {
|
|
27061
27116
|
const options = Object.assign({}, opts);
|
|
27062
27117
|
const parsed = {
|
|
27063
27118
|
scheme: void 0,
|
|
@@ -27068,6 +27123,7 @@ var require_fast_uri = __commonJS({
|
|
|
27068
27123
|
query: void 0,
|
|
27069
27124
|
fragment: void 0
|
|
27070
27125
|
};
|
|
27126
|
+
let malformedAuthorityOrPort = false;
|
|
27071
27127
|
let isIP = false;
|
|
27072
27128
|
if (options.reference === "suffix") {
|
|
27073
27129
|
if (options.scheme) {
|
|
@@ -27088,6 +27144,11 @@ var require_fast_uri = __commonJS({
|
|
|
27088
27144
|
if (isNaN(parsed.port)) {
|
|
27089
27145
|
parsed.port = matches[5];
|
|
27090
27146
|
}
|
|
27147
|
+
const parseError = getParseError(parsed, matches);
|
|
27148
|
+
if (parseError !== void 0) {
|
|
27149
|
+
parsed.error = parsed.error || parseError;
|
|
27150
|
+
malformedAuthorityOrPort = true;
|
|
27151
|
+
}
|
|
27091
27152
|
if (parsed.host) {
|
|
27092
27153
|
const ipv4result = isIPv4(parsed.host);
|
|
27093
27154
|
if (ipv4result === false) {
|
|
@@ -27126,14 +27187,18 @@ var require_fast_uri = __commonJS({
|
|
|
27126
27187
|
parsed.scheme = unescape(parsed.scheme);
|
|
27127
27188
|
}
|
|
27128
27189
|
if (parsed.host !== void 0) {
|
|
27129
|
-
parsed.host = unescape(parsed.host);
|
|
27190
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
27130
27191
|
}
|
|
27131
27192
|
}
|
|
27132
27193
|
if (parsed.path) {
|
|
27133
|
-
parsed.path =
|
|
27194
|
+
parsed.path = normalizePathEncoding(parsed.path);
|
|
27134
27195
|
}
|
|
27135
27196
|
if (parsed.fragment) {
|
|
27136
|
-
|
|
27197
|
+
try {
|
|
27198
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
27199
|
+
} catch {
|
|
27200
|
+
parsed.error = parsed.error || "URI malformed";
|
|
27201
|
+
}
|
|
27137
27202
|
}
|
|
27138
27203
|
}
|
|
27139
27204
|
if (schemeHandler && schemeHandler.parse) {
|
|
@@ -27142,7 +27207,29 @@ var require_fast_uri = __commonJS({
|
|
|
27142
27207
|
} else {
|
|
27143
27208
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
27144
27209
|
}
|
|
27145
|
-
return parsed;
|
|
27210
|
+
return { parsed, malformedAuthorityOrPort };
|
|
27211
|
+
}
|
|
27212
|
+
function parse(uri, opts) {
|
|
27213
|
+
return parseWithStatus(uri, opts).parsed;
|
|
27214
|
+
}
|
|
27215
|
+
function normalizeString(uri, opts) {
|
|
27216
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
27217
|
+
}
|
|
27218
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
27219
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
27220
|
+
return {
|
|
27221
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
27222
|
+
malformedAuthorityOrPort
|
|
27223
|
+
};
|
|
27224
|
+
}
|
|
27225
|
+
function normalizeComparableURI(uri, opts) {
|
|
27226
|
+
if (typeof uri === "string") {
|
|
27227
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
|
|
27228
|
+
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
27229
|
+
}
|
|
27230
|
+
if (typeof uri === "object") {
|
|
27231
|
+
return serialize(uri, opts);
|
|
27232
|
+
}
|
|
27146
27233
|
}
|
|
27147
27234
|
var fastUri = {
|
|
27148
27235
|
SCHEMES,
|
|
@@ -31377,7 +31464,7 @@ var init_release = __esm({
|
|
|
31377
31464
|
"../../packages/shared/src/release.ts"() {
|
|
31378
31465
|
"use strict";
|
|
31379
31466
|
init_cjs_shims();
|
|
31380
|
-
BOOTSPRING_VERSION = "3.
|
|
31467
|
+
BOOTSPRING_VERSION = "3.1.0";
|
|
31381
31468
|
BOOTSPRING_PACKAGE_NAME = "@girardmedia/bootspring";
|
|
31382
31469
|
}
|
|
31383
31470
|
});
|
|
@@ -47601,7 +47688,7 @@ var require_dist2 = __commonJS({
|
|
|
47601
47688
|
));
|
|
47602
47689
|
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
47603
47690
|
var init_cjs_shims2 = __esm2({
|
|
47604
|
-
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.
|
|
47691
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js"() {
|
|
47605
47692
|
"use strict";
|
|
47606
47693
|
}
|
|
47607
47694
|
});
|
|
@@ -52278,7 +52365,7 @@ var require_package = __commonJS({
|
|
|
52278
52365
|
"../../../package.json"(exports2, module2) {
|
|
52279
52366
|
module2.exports = {
|
|
52280
52367
|
name: "bootspring-workspace",
|
|
52281
|
-
version: "3.
|
|
52368
|
+
version: "3.1.0",
|
|
52282
52369
|
private: true,
|
|
52283
52370
|
description: "Workspace tooling for the Bootspring monorepo",
|
|
52284
52371
|
keywords: [
|
|
@@ -52382,8 +52469,10 @@ var require_package = __commonJS({
|
|
|
52382
52469
|
ajv: "^8.12.0"
|
|
52383
52470
|
},
|
|
52384
52471
|
minimatch: "^10.2.1",
|
|
52385
|
-
hono: "4.12.
|
|
52386
|
-
"@hono/node-server": "1.19.
|
|
52472
|
+
hono: "4.12.18",
|
|
52473
|
+
"@hono/node-server": "1.19.13",
|
|
52474
|
+
axios: ">=1.16.0",
|
|
52475
|
+
"simple-git": ">=3.36.0",
|
|
52387
52476
|
"express-rate-limit": "^8.2.2",
|
|
52388
52477
|
"path-to-regexp@<0.1.13": "0.1.13",
|
|
52389
52478
|
"path-to-regexp@>=8.0.0 <8.4.0": "8.4.0",
|
|
@@ -52486,9 +52575,100 @@ function formatBuildTask(task) {
|
|
|
52486
52575
|
phase: task.phase,
|
|
52487
52576
|
source: task.source,
|
|
52488
52577
|
sourceSection: task.sourceSection,
|
|
52489
|
-
acceptanceCriteria: task.acceptanceCriteria || []
|
|
52578
|
+
acceptanceCriteria: task.acceptanceCriteria || [],
|
|
52579
|
+
dependencies: task.dependencies || []
|
|
52490
52580
|
};
|
|
52491
52581
|
}
|
|
52582
|
+
function autoCommitTask(taskId, taskTitle) {
|
|
52583
|
+
try {
|
|
52584
|
+
const { execSync } = require("child_process");
|
|
52585
|
+
const cwd = getProjectRoot();
|
|
52586
|
+
const status = execSync("git status --porcelain", { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
52587
|
+
if (!status) return { committed: false, reason: "no_changes" };
|
|
52588
|
+
execSync("git add -A", { cwd, stdio: ["ignore", "ignore", "ignore"] });
|
|
52589
|
+
const msg = `feat(${taskId}): ${taskTitle}`;
|
|
52590
|
+
execSync(`git commit -m ${JSON.stringify(msg)}`, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
52591
|
+
return { committed: true, message: msg };
|
|
52592
|
+
} catch (e) {
|
|
52593
|
+
return { committed: false, reason: "git_error", error: String(e?.message || e).slice(0, 200) };
|
|
52594
|
+
}
|
|
52595
|
+
}
|
|
52596
|
+
function verifyQuality() {
|
|
52597
|
+
try {
|
|
52598
|
+
const { execSync } = require("child_process");
|
|
52599
|
+
const cwd = getProjectRoot();
|
|
52600
|
+
const fs3 = require("fs");
|
|
52601
|
+
const path3 = require("path");
|
|
52602
|
+
const pkgPath = path3.join(cwd, "package.json");
|
|
52603
|
+
if (!fs3.existsSync(pkgPath)) return { verified: true, skipped: true };
|
|
52604
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
52605
|
+
const hasTest = pkg.scripts?.test;
|
|
52606
|
+
const hasTypecheck = pkg.scripts?.typecheck;
|
|
52607
|
+
const results = { verified: true, checks: [] };
|
|
52608
|
+
if (hasTypecheck) {
|
|
52609
|
+
try {
|
|
52610
|
+
execSync("npm run typecheck 2>&1", { cwd, encoding: "utf8", timeout: 6e4, stdio: ["ignore", "pipe", "pipe"] });
|
|
52611
|
+
results.checks.push({ name: "typecheck", passed: true });
|
|
52612
|
+
} catch (e) {
|
|
52613
|
+
results.checks.push({ name: "typecheck", passed: false, error: String(e?.stdout || e?.message || "").slice(0, 500) });
|
|
52614
|
+
results.verified = false;
|
|
52615
|
+
}
|
|
52616
|
+
}
|
|
52617
|
+
if (hasTest && pkg.devDependencies?.vitest) {
|
|
52618
|
+
try {
|
|
52619
|
+
const changed = execSync("git diff --name-only HEAD 2>/dev/null || true", { cwd, encoding: "utf8" }).trim();
|
|
52620
|
+
const testFiles = changed.split("\n").filter((f) => f.match(/\.(test|spec)\.(ts|js|tsx|jsx)$/));
|
|
52621
|
+
if (testFiles.length > 0) {
|
|
52622
|
+
execSync(`npx vitest run ${testFiles.join(" ")} 2>&1`, { cwd, encoding: "utf8", timeout: 12e4, stdio: ["ignore", "pipe", "pipe"] });
|
|
52623
|
+
results.checks.push({ name: "tests", passed: true, files: testFiles.length });
|
|
52624
|
+
} else {
|
|
52625
|
+
results.checks.push({ name: "tests", passed: true, skipped: true, reason: "no_changed_test_files" });
|
|
52626
|
+
}
|
|
52627
|
+
} catch (e) {
|
|
52628
|
+
results.checks.push({ name: "tests", passed: false, error: String(e?.stdout || e?.message || "").slice(0, 500) });
|
|
52629
|
+
results.verified = false;
|
|
52630
|
+
}
|
|
52631
|
+
}
|
|
52632
|
+
return results;
|
|
52633
|
+
} catch {
|
|
52634
|
+
return { verified: true, skipped: true };
|
|
52635
|
+
}
|
|
52636
|
+
}
|
|
52637
|
+
function loadHandoff() {
|
|
52638
|
+
const fs3 = require("fs");
|
|
52639
|
+
const path3 = require("path");
|
|
52640
|
+
const handoffPath = path3.join(getProjectRoot(), "planning", ".handoff.json");
|
|
52641
|
+
if (!fs3.existsSync(handoffPath)) return null;
|
|
52642
|
+
try {
|
|
52643
|
+
return JSON.parse(fs3.readFileSync(handoffPath, "utf-8"));
|
|
52644
|
+
} catch {
|
|
52645
|
+
return null;
|
|
52646
|
+
}
|
|
52647
|
+
}
|
|
52648
|
+
function saveHandoff(data) {
|
|
52649
|
+
const fs3 = require("fs");
|
|
52650
|
+
const path3 = require("path");
|
|
52651
|
+
const planDir = path3.join(getProjectRoot(), "planning");
|
|
52652
|
+
if (!fs3.existsSync(planDir)) fs3.mkdirSync(planDir, { recursive: true });
|
|
52653
|
+
fs3.writeFileSync(path3.join(planDir, ".handoff.json"), JSON.stringify(data, null, 2));
|
|
52654
|
+
}
|
|
52655
|
+
function getBatchTasks(state, count) {
|
|
52656
|
+
const q = state?.implementationQueue || [];
|
|
52657
|
+
const pending = [];
|
|
52658
|
+
for (const task of q) {
|
|
52659
|
+
if (task.status !== "pending") continue;
|
|
52660
|
+
if (task.dependencies?.length > 0) {
|
|
52661
|
+
const allDone = task.dependencies.every((depId) => {
|
|
52662
|
+
const dep = q.find((t) => t.id === depId);
|
|
52663
|
+
return dep && dep.status === "completed";
|
|
52664
|
+
});
|
|
52665
|
+
if (!allDone) continue;
|
|
52666
|
+
}
|
|
52667
|
+
pending.push(task);
|
|
52668
|
+
if (pending.length >= count) break;
|
|
52669
|
+
}
|
|
52670
|
+
return pending;
|
|
52671
|
+
}
|
|
52492
52672
|
async function executeLocalBuild(args) {
|
|
52493
52673
|
const action = args?.action || "status";
|
|
52494
52674
|
const state = loadBuildState();
|
|
@@ -52565,6 +52745,8 @@ async function executeLocalBuild(args) {
|
|
|
52565
52745
|
if (!inProgress) {
|
|
52566
52746
|
return { content: [{ type: "text", text: JSON.stringify({ error: "No task currently in progress", hint: "Use action=next to get a task first" }, null, 2) }] };
|
|
52567
52747
|
}
|
|
52748
|
+
const quality = args?.verify !== false ? verifyQuality() : { verified: true, skipped: true };
|
|
52749
|
+
const commitResult = args?.autoCommit !== false ? autoCommitTask(inProgress.id, inProgress.title) : { committed: false, reason: "disabled" };
|
|
52568
52750
|
buildUpdateTaskStatus(state, inProgress.id, "completed");
|
|
52569
52751
|
const nextTask = buildGetNextTask(state);
|
|
52570
52752
|
if (nextTask) {
|
|
@@ -52574,10 +52756,13 @@ async function executeLocalBuild(args) {
|
|
|
52574
52756
|
const stats = buildGetStats(state);
|
|
52575
52757
|
return { content: [{ type: "text", text: JSON.stringify({
|
|
52576
52758
|
completed: { id: inProgress.id, title: inProgress.title },
|
|
52759
|
+
commit: commitResult,
|
|
52760
|
+
quality,
|
|
52577
52761
|
progress: { completed: stats.completed, total: stats.total, percent: stats.percent },
|
|
52578
52762
|
nextTask: nextTask ? { ...formatBuildTask(nextTask), file: "planning/TODO.md" } : null,
|
|
52579
52763
|
allComplete: !nextTask,
|
|
52580
|
-
|
|
52764
|
+
state: nextTask ? "advanced" : "all_complete",
|
|
52765
|
+
message: nextTask ? `Done! Committed ${inProgress.id}. Next: ${nextTask.id} \u2014 ${nextTask.title}` : "Build complete! All tasks finished."
|
|
52581
52766
|
}, null, 2) }] };
|
|
52582
52767
|
}
|
|
52583
52768
|
case "skip": {
|
|
@@ -52799,8 +52984,66 @@ async function executeLocalBuild(args) {
|
|
|
52799
52984
|
message: marked.length > 0 ? `Marked ${marked.length} task${marked.length === 1 ? "" : "s"} as completed from git history` : `Scanned ${lines.length} commits, found ${foundIds.size} bs-IDs, but none matched pending/in-progress tasks`
|
|
52800
52985
|
}, null, 2) }] };
|
|
52801
52986
|
}
|
|
52987
|
+
case "handoff": {
|
|
52988
|
+
if (args?.save) {
|
|
52989
|
+
const handoffData = {
|
|
52990
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
52991
|
+
lastTaskId: args.lastTaskId || null,
|
|
52992
|
+
inProgressTask: state ? (state.implementationQueue || []).find((t) => t.status === "in_progress")?.id || null : null,
|
|
52993
|
+
filesModified: args.filesModified || [],
|
|
52994
|
+
notes: args.notes || "",
|
|
52995
|
+
blockers: args.blockers || [],
|
|
52996
|
+
progress: state ? buildGetStats(state) : null
|
|
52997
|
+
};
|
|
52998
|
+
saveHandoff(handoffData);
|
|
52999
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
53000
|
+
saved: true,
|
|
53001
|
+
handoff: handoffData,
|
|
53002
|
+
message: "Session handoff saved. Next session will pick up from here."
|
|
53003
|
+
}, null, 2) }] };
|
|
53004
|
+
}
|
|
53005
|
+
const handoff = loadHandoff();
|
|
53006
|
+
if (!handoff) {
|
|
53007
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
53008
|
+
hasHandoff: false,
|
|
53009
|
+
message: "No previous session handoff found. Start fresh with action=next."
|
|
53010
|
+
}, null, 2) }] };
|
|
53011
|
+
}
|
|
53012
|
+
const currentState = state ? buildGetStats(state) : null;
|
|
53013
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
53014
|
+
hasHandoff: true,
|
|
53015
|
+
handoff,
|
|
53016
|
+
currentProgress: currentState,
|
|
53017
|
+
message: `Previous session left off at ${handoff.inProgressTask || handoff.lastTaskId || "unknown"}. ${handoff.notes || "No notes."}`,
|
|
53018
|
+
suggestedAction: handoff.inProgressTask ? "action=current to see the in-progress task" : "action=next to continue"
|
|
53019
|
+
}, null, 2) }] };
|
|
53020
|
+
}
|
|
53021
|
+
case "batch": {
|
|
53022
|
+
if (!state) {
|
|
53023
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "No build state found" }, null, 2) }] };
|
|
53024
|
+
}
|
|
53025
|
+
const count = Math.min(Math.max(args?.count || 5, 1), 10);
|
|
53026
|
+
const batchTasks = getBatchTasks(state, count);
|
|
53027
|
+
if (batchTasks.length === 0) {
|
|
53028
|
+
const stats = buildGetStats(state);
|
|
53029
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
53030
|
+
message: "No eligible pending tasks",
|
|
53031
|
+
progress: stats
|
|
53032
|
+
}, null, 2) }] };
|
|
53033
|
+
}
|
|
53034
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
53035
|
+
batch: batchTasks.map(formatBuildTask),
|
|
53036
|
+
count: batchTasks.length,
|
|
53037
|
+
instructions: [
|
|
53038
|
+
"Implement all tasks in this batch",
|
|
53039
|
+
"For each completed task, call action=done",
|
|
53040
|
+
"Tasks are ordered by dependency \u2014 complete them in order",
|
|
53041
|
+
"If stuck on one, call action=skip and continue with the next"
|
|
53042
|
+
]
|
|
53043
|
+
}, null, 2) }] };
|
|
53044
|
+
}
|
|
52802
53045
|
default:
|
|
52803
|
-
return { content: [{ type: "text", text: JSON.stringify({ error: `Unknown action: ${action}`, validActions: ["next", "current", "done", "skip", "status", "list", "init", "sync", "advance", "scan"] }, null, 2) }] };
|
|
53046
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Unknown action: ${action}`, validActions: ["next", "current", "done", "skip", "status", "list", "init", "sync", "advance", "scan", "handoff", "batch"] }, null, 2) }] };
|
|
52804
53047
|
}
|
|
52805
53048
|
}
|
|
52806
53049
|
async function executeLocalSeed(args) {
|
|
@@ -53058,13 +53301,31 @@ var FALLBACK_TOOLS = [
|
|
|
53058
53301
|
},
|
|
53059
53302
|
{
|
|
53060
53303
|
name: "bootspring_build",
|
|
53061
|
-
description:
|
|
53304
|
+
description: `Autonomous build loop. Manages task queue with auto-commit and quality verification.
|
|
53305
|
+
|
|
53306
|
+
Core loop: next -> implement -> done -> (auto-advances to next task)
|
|
53307
|
+
- action=done auto-commits with conventional message and returns next task
|
|
53308
|
+
- action=batch returns multiple tasks for efficient batch execution
|
|
53309
|
+
- action=handoff saves/loads session state for cross-session continuity
|
|
53310
|
+
- Dependencies are checked automatically \u2014 blocked tasks are skipped`,
|
|
53062
53311
|
inputSchema: {
|
|
53063
53312
|
type: "object",
|
|
53064
53313
|
properties: {
|
|
53065
|
-
action: {
|
|
53066
|
-
|
|
53067
|
-
|
|
53314
|
+
action: {
|
|
53315
|
+
type: "string",
|
|
53316
|
+
enum: ["next", "current", "done", "skip", "status", "list", "init", "sync", "advance", "scan", "handoff", "batch"],
|
|
53317
|
+
description: "next: get next task | done: mark complete + auto-commit + return next | batch: get N tasks | handoff: save/load session state | advance: autonomous state machine"
|
|
53318
|
+
},
|
|
53319
|
+
reason: { type: "string", description: "Reason for skipping (action=skip)" },
|
|
53320
|
+
autoDone: { type: "boolean", description: "Auto-complete if git is clean (action=advance)" },
|
|
53321
|
+
autoCommit: { type: "boolean", description: "Auto-commit on done (default: true)" },
|
|
53322
|
+
verify: { type: "boolean", description: "Run quality checks before done (default: true)" },
|
|
53323
|
+
count: { type: "number", description: "Number of tasks to return (action=batch, max 10)" },
|
|
53324
|
+
save: { type: "boolean", description: "Save handoff state (action=handoff)" },
|
|
53325
|
+
notes: { type: "string", description: "Handoff notes for next session (action=handoff save)" },
|
|
53326
|
+
filesModified: { type: "array", items: { type: "string" }, description: "Files modified this session (action=handoff save)" },
|
|
53327
|
+
blockers: { type: "array", items: { type: "string" }, description: "Unresolved blockers (action=handoff save)" },
|
|
53328
|
+
lastTaskId: { type: "string", description: "Last completed task ID (action=handoff save)" }
|
|
53068
53329
|
},
|
|
53069
53330
|
required: ["action"]
|
|
53070
53331
|
}
|
package/package.json
CHANGED
package/scripts/postinstall.cjs
CHANGED
|
@@ -33,7 +33,13 @@ function resolveCommandsSource() {
|
|
|
33
33
|
|
|
34
34
|
const COMMANDS_SOURCE = resolveCommandsSource();
|
|
35
35
|
|
|
36
|
-
const BOOTSPRING_SKILL_CONTENT =
|
|
36
|
+
const BOOTSPRING_SKILL_CONTENT = `---
|
|
37
|
+
name: bootspring
|
|
38
|
+
description: Bootspring MCP Operating Skill
|
|
39
|
+
version: 1.0.0
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# Bootspring MCP Operating Skill
|
|
37
43
|
|
|
38
44
|
Use Bootspring MCP tools as the primary workflow for any project with Bootspring configured.
|
|
39
45
|
These tools work via MCP protocol with any assistant: Claude Code, Codex, Gemini CLI, or others.
|