@akanjs/cli 2.3.11-rc.2 → 2.3.11-rc.4
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/incrementalBuilder.proc.js +173 -7
- package/index.js +415 -14
- package/package.json +2 -2
- package/templates/workspaceRoot/.gitignore.template +2 -1
|
@@ -4170,6 +4170,7 @@ var BACKEND_RESTART_DEBOUNCE_MS = 120;
|
|
|
4170
4170
|
var BACKEND_GRACEFUL_TIMEOUT_MS = 3000;
|
|
4171
4171
|
var BACKEND_RECOVERY_BASE_DELAY_MS = 1000;
|
|
4172
4172
|
var BACKEND_RECOVERY_MAX_DELAY_MS = 30000;
|
|
4173
|
+
var BACKEND_STDERR_TAIL_LIMIT = 40;
|
|
4173
4174
|
var BUILDER_READY_TIMEOUT_MS = 150000;
|
|
4174
4175
|
var BUILDER_START_MAX_ATTEMPTS = 3;
|
|
4175
4176
|
var SOURCE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
@@ -4372,6 +4373,7 @@ class AkanAppHost {
|
|
|
4372
4373
|
#pendingRestartReason = null;
|
|
4373
4374
|
#backendStartStatus = null;
|
|
4374
4375
|
#backendBuildStatusGeneration = 0;
|
|
4376
|
+
#backendStderrTail = [];
|
|
4375
4377
|
#lastGoodFrontend = {};
|
|
4376
4378
|
#buildStatusByPhase = new Map;
|
|
4377
4379
|
#pendingBuildStatusReplay = [];
|
|
@@ -4423,6 +4425,7 @@ class AkanAppHost {
|
|
|
4423
4425
|
this.#backendStartStatus = startStatus;
|
|
4424
4426
|
this.#setBackendLifecycleState("starting");
|
|
4425
4427
|
this.#backendReady = false;
|
|
4428
|
+
this.#backendStderrTail = [];
|
|
4426
4429
|
const backend = Bun.spawn(["bun", `apps/${this.app.name}/main.ts`], {
|
|
4427
4430
|
cwd: this.app.workspace.workspaceRoot,
|
|
4428
4431
|
stdio: this.withInk ? ["ignore", "pipe", "pipe"] : ["inherit", "inherit", "inherit"],
|
|
@@ -4456,6 +4459,37 @@ class AkanAppHost {
|
|
|
4456
4459
|
});
|
|
4457
4460
|
this.#backend = backend;
|
|
4458
4461
|
this.logger.verbose(`backend spawned pid=${backend.pid}`);
|
|
4462
|
+
if (this.withInk) {
|
|
4463
|
+
this.#forwardBackendStream(backend.stderr, "stderr");
|
|
4464
|
+
this.#forwardBackendStream(backend.stdout, "stdout");
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
#recordBackendStderr(chunk) {
|
|
4468
|
+
const lines = chunk.split(/\r?\n/).filter((line) => line.length > 0);
|
|
4469
|
+
if (lines.length === 0)
|
|
4470
|
+
return;
|
|
4471
|
+
this.#backendStderrTail.push(...lines);
|
|
4472
|
+
if (this.#backendStderrTail.length > BACKEND_STDERR_TAIL_LIMIT) {
|
|
4473
|
+
this.#backendStderrTail.splice(0, this.#backendStderrTail.length - BACKEND_STDERR_TAIL_LIMIT);
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
async#forwardBackendStream(stream, kind) {
|
|
4477
|
+
if (!stream)
|
|
4478
|
+
return;
|
|
4479
|
+
const decoder = new TextDecoder;
|
|
4480
|
+
try {
|
|
4481
|
+
for await (const chunk of stream) {
|
|
4482
|
+
const text = decoder.decode(chunk, { stream: true });
|
|
4483
|
+
if (!text.trim())
|
|
4484
|
+
continue;
|
|
4485
|
+
if (kind === "stderr") {
|
|
4486
|
+
this.#recordBackendStderr(text);
|
|
4487
|
+
this.logger.warn(`[backend] ${text.trimEnd()}`);
|
|
4488
|
+
} else {
|
|
4489
|
+
this.logger.verbose(`[backend] ${text.trimEnd()}`);
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
} catch {}
|
|
4459
4493
|
}
|
|
4460
4494
|
#nextBackendBuildStatusGeneration(generation) {
|
|
4461
4495
|
if (typeof generation === "number") {
|
|
@@ -4580,6 +4614,11 @@ class AkanAppHost {
|
|
|
4580
4614
|
});
|
|
4581
4615
|
this.#sendOrQueueBuildStatus(failureStatus);
|
|
4582
4616
|
this.logger.warn(`[backend-recovery] backend exited unexpectedly (${reason}); restarting in ${delay}ms (attempt ${this.#backendRecoveryAttempts})`);
|
|
4617
|
+
if (this.#backendStderrTail.length > 0) {
|
|
4618
|
+
this.logger.warn(`[backend-recovery] recent backend stderr:
|
|
4619
|
+
${this.#backendStderrTail.join(`
|
|
4620
|
+
`)}`);
|
|
4621
|
+
}
|
|
4583
4622
|
this.#backendRecoveryTimer = setTimeout(() => {
|
|
4584
4623
|
this.#backendRecoveryTimer = null;
|
|
4585
4624
|
if (this.#backend)
|
|
@@ -5945,6 +5984,117 @@ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${
|
|
|
5945
5984
|
return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
|
|
5946
5985
|
};
|
|
5947
5986
|
var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
5987
|
+
var hasSourceParseErrors = (content, fileName = "source.ts") => hasParseDiagnostics(sourceFileFor(fileName, content));
|
|
5988
|
+
var findClassDeclaration = (source, className) => {
|
|
5989
|
+
let found = null;
|
|
5990
|
+
const visit = (node) => {
|
|
5991
|
+
if (found)
|
|
5992
|
+
return;
|
|
5993
|
+
if (ts4.isClassDeclaration(node) && node.name?.text === className) {
|
|
5994
|
+
found = node;
|
|
5995
|
+
return;
|
|
5996
|
+
}
|
|
5997
|
+
ts4.forEachChild(node, visit);
|
|
5998
|
+
};
|
|
5999
|
+
ts4.forEachChild(source, visit);
|
|
6000
|
+
return found;
|
|
6001
|
+
};
|
|
6002
|
+
var firstHeritageCall = (node) => {
|
|
6003
|
+
const expression = (node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [])[0]?.expression;
|
|
6004
|
+
return expression && ts4.isCallExpression(expression) ? expression : null;
|
|
6005
|
+
};
|
|
6006
|
+
var factoryArrowOf = (call) => {
|
|
6007
|
+
const arg = call.arguments.find((argument) => ts4.isArrowFunction(argument) || ts4.isFunctionExpression(argument));
|
|
6008
|
+
return arg && (ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg)) ? arg : null;
|
|
6009
|
+
};
|
|
6010
|
+
var hasClassMethod = (content, className, methodName) => {
|
|
6011
|
+
const node = findClassDeclaration(sourceFileFor("service.ts", content), className);
|
|
6012
|
+
return Boolean(node?.members.some((member) => ts4.isMethodDeclaration(member) && nodeName(member.name) === methodName));
|
|
6013
|
+
};
|
|
6014
|
+
var insertClassMethod = (content, className, methodBlock) => {
|
|
6015
|
+
const source = sourceFileFor("service.ts", content);
|
|
6016
|
+
const node = findClassDeclaration(source, className);
|
|
6017
|
+
if (!node)
|
|
6018
|
+
return null;
|
|
6019
|
+
const closeBrace = node.getEnd() - 1;
|
|
6020
|
+
if (content[closeBrace] !== "}")
|
|
6021
|
+
return null;
|
|
6022
|
+
const lead = content.slice(0, closeBrace).endsWith(`
|
|
6023
|
+
`) ? "" : `
|
|
6024
|
+
`;
|
|
6025
|
+
return spliceText(content, closeBrace, closeBrace, `${lead}${methodBlock}
|
|
6026
|
+
`);
|
|
6027
|
+
};
|
|
6028
|
+
var arrowParamInnerRegion = (content, source, arrow) => {
|
|
6029
|
+
if (arrow.parameters.length > 0) {
|
|
6030
|
+
return {
|
|
6031
|
+
start: arrow.parameters[0].getStart(source),
|
|
6032
|
+
end: arrow.parameters[arrow.parameters.length - 1].getEnd()
|
|
6033
|
+
};
|
|
6034
|
+
}
|
|
6035
|
+
const open = content.indexOf("(", arrow.getStart(source));
|
|
6036
|
+
if (open < 0)
|
|
6037
|
+
return null;
|
|
6038
|
+
const close = content.indexOf(")", open);
|
|
6039
|
+
if (close < 0)
|
|
6040
|
+
return null;
|
|
6041
|
+
return { start: open + 1, end: close };
|
|
6042
|
+
};
|
|
6043
|
+
var factoryParamEdit = (content, source, arrow, plan) => {
|
|
6044
|
+
if (arrow.parameters.length > 1)
|
|
6045
|
+
return null;
|
|
6046
|
+
const region = arrowParamInnerRegion(content, source, arrow);
|
|
6047
|
+
if (!region)
|
|
6048
|
+
return null;
|
|
6049
|
+
if (arrow.parameters.length === 0) {
|
|
6050
|
+
return { ...region, text: plan.mode === "destructure" ? `{ ${plan.name} }` : plan.name };
|
|
6051
|
+
}
|
|
6052
|
+
const param = arrow.parameters[0];
|
|
6053
|
+
if (plan.mode === "positional")
|
|
6054
|
+
return nodeName(param.name) === plan.name ? "unchanged" : null;
|
|
6055
|
+
if (!ts4.isObjectBindingPattern(param.name))
|
|
6056
|
+
return null;
|
|
6057
|
+
const names = param.name.elements.map((element) => ts4.isIdentifier(element.name) ? element.name.text : null);
|
|
6058
|
+
if (names.some((name) => name === null))
|
|
6059
|
+
return null;
|
|
6060
|
+
if (names.includes(plan.name))
|
|
6061
|
+
return "unchanged";
|
|
6062
|
+
return {
|
|
6063
|
+
start: param.getStart(source),
|
|
6064
|
+
end: param.getEnd(),
|
|
6065
|
+
text: `{ ${[...names, plan.name].join(", ")} }`
|
|
6066
|
+
};
|
|
6067
|
+
};
|
|
6068
|
+
var factoryObjectOf = (source, className) => {
|
|
6069
|
+
const node = findClassDeclaration(source, className);
|
|
6070
|
+
const call = node ? firstHeritageCall(node) : null;
|
|
6071
|
+
const arrow = call ? factoryArrowOf(call) : null;
|
|
6072
|
+
const object = arrow ? firstObjectReturnedByArrow(arrow) : null;
|
|
6073
|
+
return arrow && object ? { arrow, object } : null;
|
|
6074
|
+
};
|
|
6075
|
+
var hasSignalFactoryEntry = (content, className, entryName) => {
|
|
6076
|
+
const located = factoryObjectOf(sourceFileFor("signal.ts", content), className);
|
|
6077
|
+
return Boolean(located?.object.properties.some((property) => propertyName(property) === entryName));
|
|
6078
|
+
};
|
|
6079
|
+
var insertSignalFactoryEntry = (content, className, entryName, entryLine, param) => {
|
|
6080
|
+
const source = sourceFileFor("signal.ts", content);
|
|
6081
|
+
const located = factoryObjectOf(source, className);
|
|
6082
|
+
if (!located)
|
|
6083
|
+
return null;
|
|
6084
|
+
const locator = locatedObject(source, located.object);
|
|
6085
|
+
if (locator.fields.some((field) => field.name === entryName))
|
|
6086
|
+
return content;
|
|
6087
|
+
const paramEdit = factoryParamEdit(content, source, located.arrow, param);
|
|
6088
|
+
if (paramEdit === null)
|
|
6089
|
+
return null;
|
|
6090
|
+
const withEntry = insertOrderedFieldLine(content, locator, entryName, entryLine, {
|
|
6091
|
+
fieldIndent: " ",
|
|
6092
|
+
closingIndent: ""
|
|
6093
|
+
});
|
|
6094
|
+
if (withEntry === content)
|
|
6095
|
+
return null;
|
|
6096
|
+
return paramEdit === "unchanged" ? withEntry : spliceText(withEntry, paramEdit.start, paramEdit.end, paramEdit.text);
|
|
6097
|
+
};
|
|
5948
6098
|
|
|
5949
6099
|
// pkgs/@akanjs/devkit/workflow/moduleIndex.ts
|
|
5950
6100
|
var indexFileKinds = [
|
|
@@ -6662,7 +6812,9 @@ var createWorkflowStepRegistry = ({
|
|
|
6662
6812
|
createScalar,
|
|
6663
6813
|
createUi,
|
|
6664
6814
|
addField,
|
|
6665
|
-
addEnumField
|
|
6815
|
+
addEnumField,
|
|
6816
|
+
addMutation,
|
|
6817
|
+
addSlice
|
|
6666
6818
|
}) => {
|
|
6667
6819
|
const inspect = async () => {
|
|
6668
6820
|
return;
|
|
@@ -6738,7 +6890,19 @@ var createWorkflowStepRegistry = ({
|
|
|
6738
6890
|
defaultValue: workflowStringInput(plan.inputs.default)
|
|
6739
6891
|
})),
|
|
6740
6892
|
[workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
|
|
6741
|
-
[workflowStepKey("add-enum-field", "update-option")]: inspect
|
|
6893
|
+
[workflowStepKey("add-enum-field", "update-option")]: inspect,
|
|
6894
|
+
[workflowStepKey("add-mutation", "update-service")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addMutation({
|
|
6895
|
+
app: workflowStringInput(plan.inputs.app),
|
|
6896
|
+
module: workflowStringInput(plan.inputs.module),
|
|
6897
|
+
mutation: workflowStringInput(plan.inputs.mutation)
|
|
6898
|
+
})),
|
|
6899
|
+
[workflowStepKey("add-mutation", "update-signal")]: inspect,
|
|
6900
|
+
[workflowStepKey("add-slice", "update-service-query")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addSlice({
|
|
6901
|
+
app: workflowStringInput(plan.inputs.app),
|
|
6902
|
+
module: workflowStringInput(plan.inputs.module),
|
|
6903
|
+
slice: workflowStringInput(plan.inputs.slice)
|
|
6904
|
+
})),
|
|
6905
|
+
[workflowStepKey("add-slice", "update-signal-slice")]: inspect
|
|
6742
6906
|
};
|
|
6743
6907
|
};
|
|
6744
6908
|
class WorkflowExecutor {
|
|
@@ -12807,11 +12971,15 @@ async function resolveSignalTestPreloadPath(target) {
|
|
|
12807
12971
|
addResolvedPackageCandidate(path39.dirname(Bun.main));
|
|
12808
12972
|
addResolvedPackageCandidate(import.meta.dir);
|
|
12809
12973
|
candidates.push(path39.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(path39.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
|
|
12810
|
-
|
|
12974
|
+
const uniqueCandidates = [...new Set(candidates)];
|
|
12975
|
+
for (const candidate of uniqueCandidates) {
|
|
12811
12976
|
if (await Bun.file(candidate).exists())
|
|
12812
12977
|
return candidate;
|
|
12813
12978
|
}
|
|
12814
|
-
throw new Error(`Failed to locate ${SIGNAL_TEST_PRELOAD_PATH} from ${target.cwdPath}
|
|
12979
|
+
throw new Error(`Failed to locate ${SIGNAL_TEST_PRELOAD_PATH} from ${target.cwdPath}.
|
|
12980
|
+
Probed paths:
|
|
12981
|
+
${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
|
|
12982
|
+
`)}`);
|
|
12815
12983
|
}
|
|
12816
12984
|
// pkgs/@akanjs/devkit/builder.ts
|
|
12817
12985
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -15720,10 +15888,8 @@ function getConventionDescription(suffix, modelName) {
|
|
|
15720
15888
|
}
|
|
15721
15889
|
function getLibRootFile(file) {
|
|
15722
15890
|
const segments = file.split("/");
|
|
15723
|
-
if (segments[0] === "libs" && segments.length === 4 && segments[2] === "lib")
|
|
15891
|
+
if ((segments[0] === "libs" || segments[0] === "apps") && segments.length === 4 && segments[2] === "lib")
|
|
15724
15892
|
return segments[3];
|
|
15725
|
-
if (segments[0] === "apps" && segments.length === 5 && segments[2] === "lib")
|
|
15726
|
-
return segments[4];
|
|
15727
15893
|
return null;
|
|
15728
15894
|
}
|
|
15729
15895
|
function getModuleUiWarning(file) {
|
package/index.js
CHANGED
|
@@ -4168,6 +4168,7 @@ var BACKEND_RESTART_DEBOUNCE_MS = 120;
|
|
|
4168
4168
|
var BACKEND_GRACEFUL_TIMEOUT_MS = 3000;
|
|
4169
4169
|
var BACKEND_RECOVERY_BASE_DELAY_MS = 1000;
|
|
4170
4170
|
var BACKEND_RECOVERY_MAX_DELAY_MS = 30000;
|
|
4171
|
+
var BACKEND_STDERR_TAIL_LIMIT = 40;
|
|
4171
4172
|
var BUILDER_READY_TIMEOUT_MS = 150000;
|
|
4172
4173
|
var BUILDER_START_MAX_ATTEMPTS = 3;
|
|
4173
4174
|
var SOURCE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
@@ -4370,6 +4371,7 @@ class AkanAppHost {
|
|
|
4370
4371
|
#pendingRestartReason = null;
|
|
4371
4372
|
#backendStartStatus = null;
|
|
4372
4373
|
#backendBuildStatusGeneration = 0;
|
|
4374
|
+
#backendStderrTail = [];
|
|
4373
4375
|
#lastGoodFrontend = {};
|
|
4374
4376
|
#buildStatusByPhase = new Map;
|
|
4375
4377
|
#pendingBuildStatusReplay = [];
|
|
@@ -4421,6 +4423,7 @@ class AkanAppHost {
|
|
|
4421
4423
|
this.#backendStartStatus = startStatus;
|
|
4422
4424
|
this.#setBackendLifecycleState("starting");
|
|
4423
4425
|
this.#backendReady = false;
|
|
4426
|
+
this.#backendStderrTail = [];
|
|
4424
4427
|
const backend = Bun.spawn(["bun", `apps/${this.app.name}/main.ts`], {
|
|
4425
4428
|
cwd: this.app.workspace.workspaceRoot,
|
|
4426
4429
|
stdio: this.withInk ? ["ignore", "pipe", "pipe"] : ["inherit", "inherit", "inherit"],
|
|
@@ -4454,6 +4457,37 @@ class AkanAppHost {
|
|
|
4454
4457
|
});
|
|
4455
4458
|
this.#backend = backend;
|
|
4456
4459
|
this.logger.verbose(`backend spawned pid=${backend.pid}`);
|
|
4460
|
+
if (this.withInk) {
|
|
4461
|
+
this.#forwardBackendStream(backend.stderr, "stderr");
|
|
4462
|
+
this.#forwardBackendStream(backend.stdout, "stdout");
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
#recordBackendStderr(chunk) {
|
|
4466
|
+
const lines = chunk.split(/\r?\n/).filter((line) => line.length > 0);
|
|
4467
|
+
if (lines.length === 0)
|
|
4468
|
+
return;
|
|
4469
|
+
this.#backendStderrTail.push(...lines);
|
|
4470
|
+
if (this.#backendStderrTail.length > BACKEND_STDERR_TAIL_LIMIT) {
|
|
4471
|
+
this.#backendStderrTail.splice(0, this.#backendStderrTail.length - BACKEND_STDERR_TAIL_LIMIT);
|
|
4472
|
+
}
|
|
4473
|
+
}
|
|
4474
|
+
async#forwardBackendStream(stream, kind) {
|
|
4475
|
+
if (!stream)
|
|
4476
|
+
return;
|
|
4477
|
+
const decoder = new TextDecoder;
|
|
4478
|
+
try {
|
|
4479
|
+
for await (const chunk of stream) {
|
|
4480
|
+
const text = decoder.decode(chunk, { stream: true });
|
|
4481
|
+
if (!text.trim())
|
|
4482
|
+
continue;
|
|
4483
|
+
if (kind === "stderr") {
|
|
4484
|
+
this.#recordBackendStderr(text);
|
|
4485
|
+
this.logger.warn(`[backend] ${text.trimEnd()}`);
|
|
4486
|
+
} else {
|
|
4487
|
+
this.logger.verbose(`[backend] ${text.trimEnd()}`);
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
} catch {}
|
|
4457
4491
|
}
|
|
4458
4492
|
#nextBackendBuildStatusGeneration(generation) {
|
|
4459
4493
|
if (typeof generation === "number") {
|
|
@@ -4578,6 +4612,11 @@ class AkanAppHost {
|
|
|
4578
4612
|
});
|
|
4579
4613
|
this.#sendOrQueueBuildStatus(failureStatus);
|
|
4580
4614
|
this.logger.warn(`[backend-recovery] backend exited unexpectedly (${reason}); restarting in ${delay}ms (attempt ${this.#backendRecoveryAttempts})`);
|
|
4615
|
+
if (this.#backendStderrTail.length > 0) {
|
|
4616
|
+
this.logger.warn(`[backend-recovery] recent backend stderr:
|
|
4617
|
+
${this.#backendStderrTail.join(`
|
|
4618
|
+
`)}`);
|
|
4619
|
+
}
|
|
4581
4620
|
this.#backendRecoveryTimer = setTimeout(() => {
|
|
4582
4621
|
this.#backendRecoveryTimer = null;
|
|
4583
4622
|
if (this.#backend)
|
|
@@ -5943,6 +5982,117 @@ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${
|
|
|
5943
5982
|
return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
|
|
5944
5983
|
};
|
|
5945
5984
|
var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
5985
|
+
var hasSourceParseErrors = (content, fileName = "source.ts") => hasParseDiagnostics(sourceFileFor(fileName, content));
|
|
5986
|
+
var findClassDeclaration = (source, className) => {
|
|
5987
|
+
let found = null;
|
|
5988
|
+
const visit = (node) => {
|
|
5989
|
+
if (found)
|
|
5990
|
+
return;
|
|
5991
|
+
if (ts4.isClassDeclaration(node) && node.name?.text === className) {
|
|
5992
|
+
found = node;
|
|
5993
|
+
return;
|
|
5994
|
+
}
|
|
5995
|
+
ts4.forEachChild(node, visit);
|
|
5996
|
+
};
|
|
5997
|
+
ts4.forEachChild(source, visit);
|
|
5998
|
+
return found;
|
|
5999
|
+
};
|
|
6000
|
+
var firstHeritageCall = (node) => {
|
|
6001
|
+
const expression = (node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [])[0]?.expression;
|
|
6002
|
+
return expression && ts4.isCallExpression(expression) ? expression : null;
|
|
6003
|
+
};
|
|
6004
|
+
var factoryArrowOf = (call) => {
|
|
6005
|
+
const arg = call.arguments.find((argument) => ts4.isArrowFunction(argument) || ts4.isFunctionExpression(argument));
|
|
6006
|
+
return arg && (ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg)) ? arg : null;
|
|
6007
|
+
};
|
|
6008
|
+
var hasClassMethod = (content, className, methodName) => {
|
|
6009
|
+
const node = findClassDeclaration(sourceFileFor("service.ts", content), className);
|
|
6010
|
+
return Boolean(node?.members.some((member) => ts4.isMethodDeclaration(member) && nodeName(member.name) === methodName));
|
|
6011
|
+
};
|
|
6012
|
+
var insertClassMethod = (content, className, methodBlock) => {
|
|
6013
|
+
const source = sourceFileFor("service.ts", content);
|
|
6014
|
+
const node = findClassDeclaration(source, className);
|
|
6015
|
+
if (!node)
|
|
6016
|
+
return null;
|
|
6017
|
+
const closeBrace = node.getEnd() - 1;
|
|
6018
|
+
if (content[closeBrace] !== "}")
|
|
6019
|
+
return null;
|
|
6020
|
+
const lead = content.slice(0, closeBrace).endsWith(`
|
|
6021
|
+
`) ? "" : `
|
|
6022
|
+
`;
|
|
6023
|
+
return spliceText(content, closeBrace, closeBrace, `${lead}${methodBlock}
|
|
6024
|
+
`);
|
|
6025
|
+
};
|
|
6026
|
+
var arrowParamInnerRegion = (content, source, arrow) => {
|
|
6027
|
+
if (arrow.parameters.length > 0) {
|
|
6028
|
+
return {
|
|
6029
|
+
start: arrow.parameters[0].getStart(source),
|
|
6030
|
+
end: arrow.parameters[arrow.parameters.length - 1].getEnd()
|
|
6031
|
+
};
|
|
6032
|
+
}
|
|
6033
|
+
const open = content.indexOf("(", arrow.getStart(source));
|
|
6034
|
+
if (open < 0)
|
|
6035
|
+
return null;
|
|
6036
|
+
const close = content.indexOf(")", open);
|
|
6037
|
+
if (close < 0)
|
|
6038
|
+
return null;
|
|
6039
|
+
return { start: open + 1, end: close };
|
|
6040
|
+
};
|
|
6041
|
+
var factoryParamEdit = (content, source, arrow, plan) => {
|
|
6042
|
+
if (arrow.parameters.length > 1)
|
|
6043
|
+
return null;
|
|
6044
|
+
const region = arrowParamInnerRegion(content, source, arrow);
|
|
6045
|
+
if (!region)
|
|
6046
|
+
return null;
|
|
6047
|
+
if (arrow.parameters.length === 0) {
|
|
6048
|
+
return { ...region, text: plan.mode === "destructure" ? `{ ${plan.name} }` : plan.name };
|
|
6049
|
+
}
|
|
6050
|
+
const param = arrow.parameters[0];
|
|
6051
|
+
if (plan.mode === "positional")
|
|
6052
|
+
return nodeName(param.name) === plan.name ? "unchanged" : null;
|
|
6053
|
+
if (!ts4.isObjectBindingPattern(param.name))
|
|
6054
|
+
return null;
|
|
6055
|
+
const names = param.name.elements.map((element) => ts4.isIdentifier(element.name) ? element.name.text : null);
|
|
6056
|
+
if (names.some((name) => name === null))
|
|
6057
|
+
return null;
|
|
6058
|
+
if (names.includes(plan.name))
|
|
6059
|
+
return "unchanged";
|
|
6060
|
+
return {
|
|
6061
|
+
start: param.getStart(source),
|
|
6062
|
+
end: param.getEnd(),
|
|
6063
|
+
text: `{ ${[...names, plan.name].join(", ")} }`
|
|
6064
|
+
};
|
|
6065
|
+
};
|
|
6066
|
+
var factoryObjectOf = (source, className) => {
|
|
6067
|
+
const node = findClassDeclaration(source, className);
|
|
6068
|
+
const call = node ? firstHeritageCall(node) : null;
|
|
6069
|
+
const arrow = call ? factoryArrowOf(call) : null;
|
|
6070
|
+
const object = arrow ? firstObjectReturnedByArrow(arrow) : null;
|
|
6071
|
+
return arrow && object ? { arrow, object } : null;
|
|
6072
|
+
};
|
|
6073
|
+
var hasSignalFactoryEntry = (content, className, entryName) => {
|
|
6074
|
+
const located = factoryObjectOf(sourceFileFor("signal.ts", content), className);
|
|
6075
|
+
return Boolean(located?.object.properties.some((property) => propertyName(property) === entryName));
|
|
6076
|
+
};
|
|
6077
|
+
var insertSignalFactoryEntry = (content, className, entryName, entryLine, param) => {
|
|
6078
|
+
const source = sourceFileFor("signal.ts", content);
|
|
6079
|
+
const located = factoryObjectOf(source, className);
|
|
6080
|
+
if (!located)
|
|
6081
|
+
return null;
|
|
6082
|
+
const locator = locatedObject(source, located.object);
|
|
6083
|
+
if (locator.fields.some((field) => field.name === entryName))
|
|
6084
|
+
return content;
|
|
6085
|
+
const paramEdit = factoryParamEdit(content, source, located.arrow, param);
|
|
6086
|
+
if (paramEdit === null)
|
|
6087
|
+
return null;
|
|
6088
|
+
const withEntry = insertOrderedFieldLine(content, locator, entryName, entryLine, {
|
|
6089
|
+
fieldIndent: " ",
|
|
6090
|
+
closingIndent: ""
|
|
6091
|
+
});
|
|
6092
|
+
if (withEntry === content)
|
|
6093
|
+
return null;
|
|
6094
|
+
return paramEdit === "unchanged" ? withEntry : spliceText(withEntry, paramEdit.start, paramEdit.end, paramEdit.text);
|
|
6095
|
+
};
|
|
5946
6096
|
|
|
5947
6097
|
// pkgs/@akanjs/devkit/workflow/moduleIndex.ts
|
|
5948
6098
|
var indexFileKinds = [
|
|
@@ -6660,7 +6810,9 @@ var createWorkflowStepRegistry = ({
|
|
|
6660
6810
|
createScalar,
|
|
6661
6811
|
createUi,
|
|
6662
6812
|
addField,
|
|
6663
|
-
addEnumField
|
|
6813
|
+
addEnumField,
|
|
6814
|
+
addMutation,
|
|
6815
|
+
addSlice
|
|
6664
6816
|
}) => {
|
|
6665
6817
|
const inspect = async () => {
|
|
6666
6818
|
return;
|
|
@@ -6736,7 +6888,19 @@ var createWorkflowStepRegistry = ({
|
|
|
6736
6888
|
defaultValue: workflowStringInput(plan.inputs.default)
|
|
6737
6889
|
})),
|
|
6738
6890
|
[workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
|
|
6739
|
-
[workflowStepKey("add-enum-field", "update-option")]: inspect
|
|
6891
|
+
[workflowStepKey("add-enum-field", "update-option")]: inspect,
|
|
6892
|
+
[workflowStepKey("add-mutation", "update-service")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addMutation({
|
|
6893
|
+
app: workflowStringInput(plan.inputs.app),
|
|
6894
|
+
module: workflowStringInput(plan.inputs.module),
|
|
6895
|
+
mutation: workflowStringInput(plan.inputs.mutation)
|
|
6896
|
+
})),
|
|
6897
|
+
[workflowStepKey("add-mutation", "update-signal")]: inspect,
|
|
6898
|
+
[workflowStepKey("add-slice", "update-service-query")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addSlice({
|
|
6899
|
+
app: workflowStringInput(plan.inputs.app),
|
|
6900
|
+
module: workflowStringInput(plan.inputs.module),
|
|
6901
|
+
slice: workflowStringInput(plan.inputs.slice)
|
|
6902
|
+
})),
|
|
6903
|
+
[workflowStepKey("add-slice", "update-signal-slice")]: inspect
|
|
6740
6904
|
};
|
|
6741
6905
|
};
|
|
6742
6906
|
class WorkflowExecutor {
|
|
@@ -12805,11 +12969,15 @@ async function resolveSignalTestPreloadPath(target) {
|
|
|
12805
12969
|
addResolvedPackageCandidate(path39.dirname(Bun.main));
|
|
12806
12970
|
addResolvedPackageCandidate(import.meta.dir);
|
|
12807
12971
|
candidates.push(path39.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.join(path39.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path39.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
|
|
12808
|
-
|
|
12972
|
+
const uniqueCandidates = [...new Set(candidates)];
|
|
12973
|
+
for (const candidate of uniqueCandidates) {
|
|
12809
12974
|
if (await Bun.file(candidate).exists())
|
|
12810
12975
|
return candidate;
|
|
12811
12976
|
}
|
|
12812
|
-
throw new Error(`Failed to locate ${SIGNAL_TEST_PRELOAD_PATH} from ${target.cwdPath}
|
|
12977
|
+
throw new Error(`Failed to locate ${SIGNAL_TEST_PRELOAD_PATH} from ${target.cwdPath}.
|
|
12978
|
+
Probed paths:
|
|
12979
|
+
${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
|
|
12980
|
+
`)}`);
|
|
12813
12981
|
}
|
|
12814
12982
|
// pkgs/@akanjs/devkit/builder.ts
|
|
12815
12983
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -15718,10 +15886,8 @@ function getConventionDescription(suffix, modelName) {
|
|
|
15718
15886
|
}
|
|
15719
15887
|
function getLibRootFile(file) {
|
|
15720
15888
|
const segments = file.split("/");
|
|
15721
|
-
if (segments[0] === "libs" && segments.length === 4 && segments[2] === "lib")
|
|
15889
|
+
if ((segments[0] === "libs" || segments[0] === "apps") && segments.length === 4 && segments[2] === "lib")
|
|
15722
15890
|
return segments[3];
|
|
15723
|
-
if (segments[0] === "apps" && segments.length === 5 && segments[2] === "lib")
|
|
15724
|
-
return segments[4];
|
|
15725
15891
|
return null;
|
|
15726
15892
|
}
|
|
15727
15893
|
function getModuleUiWarning(file) {
|
|
@@ -17999,8 +18165,18 @@ var addMutationWorkflowSpec = {
|
|
|
17999
18165
|
}
|
|
18000
18166
|
],
|
|
18001
18167
|
predictedChanges: [
|
|
18002
|
-
{
|
|
18003
|
-
|
|
18168
|
+
{
|
|
18169
|
+
target: "*/lib/<module>/<module>.service.ts",
|
|
18170
|
+
action: "modify",
|
|
18171
|
+
applyScope: "auto",
|
|
18172
|
+
reason: "Service mutation method stub is added."
|
|
18173
|
+
},
|
|
18174
|
+
{
|
|
18175
|
+
target: "*/lib/<module>/<module>.signal.ts",
|
|
18176
|
+
action: "modify",
|
|
18177
|
+
applyScope: "auto",
|
|
18178
|
+
reason: "Signal endpoint mutation is added."
|
|
18179
|
+
},
|
|
18004
18180
|
{ target: "*/lib/srv.ts", action: "sync", reason: "Generated service barrel may change after sync." },
|
|
18005
18181
|
{ target: "*/lib/sig.ts", action: "sync", reason: "Generated signal barrel may change after sync." }
|
|
18006
18182
|
],
|
|
@@ -18072,9 +18248,24 @@ var addSliceWorkflowSpec = {
|
|
|
18072
18248
|
}
|
|
18073
18249
|
],
|
|
18074
18250
|
predictedChanges: [
|
|
18075
|
-
{
|
|
18076
|
-
|
|
18077
|
-
|
|
18251
|
+
{
|
|
18252
|
+
target: "*/lib/<module>/<module>.service.ts",
|
|
18253
|
+
action: "modify",
|
|
18254
|
+
applyScope: "auto",
|
|
18255
|
+
reason: "Query helper method stub is added."
|
|
18256
|
+
},
|
|
18257
|
+
{
|
|
18258
|
+
target: "*/lib/<module>/<module>.signal.ts",
|
|
18259
|
+
action: "modify",
|
|
18260
|
+
applyScope: "auto",
|
|
18261
|
+
reason: "Signal slice entry is added."
|
|
18262
|
+
},
|
|
18263
|
+
{
|
|
18264
|
+
target: "*/lib/<module>/<Module>.Zone.tsx",
|
|
18265
|
+
action: "modify",
|
|
18266
|
+
applyScope: "manual-review",
|
|
18267
|
+
reason: "Zone may connect slice state."
|
|
18268
|
+
},
|
|
18078
18269
|
{ target: "*/lib/sig.ts", action: "sync", reason: "Generated signal barrel may change after sync." }
|
|
18079
18270
|
],
|
|
18080
18271
|
validation: [
|
|
@@ -19386,6 +19577,12 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
19386
19577
|
code: "primitive-field-type-unsupported",
|
|
19387
19578
|
message: `Field type "${input7.type}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`,
|
|
19388
19579
|
input: "type"
|
|
19580
|
+
} : null,
|
|
19581
|
+
input7.type && input7.type.toLowerCase() === "upload" ? {
|
|
19582
|
+
severity: "error",
|
|
19583
|
+
code: "primitive-field-type-upload-misuse",
|
|
19584
|
+
message: "Upload is not a model field type. Declare an image/file field as a relation to the File model (e.g. field(File)); Upload is only valid in a { fileUpload: true } signal body. Note the File model is provided by the shared file library.",
|
|
19585
|
+
input: "type"
|
|
19389
19586
|
} : null
|
|
19390
19587
|
]);
|
|
19391
19588
|
if (!sys3 || !input7.module || !input7.field || !input7.type || diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
@@ -19584,6 +19781,206 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
19584
19781
|
nextActions: nextActionsForTarget(sys3.name)
|
|
19585
19782
|
});
|
|
19586
19783
|
}
|
|
19784
|
+
async addMutation(workspace, input7) {
|
|
19785
|
+
const moduleClassName = input7.module ? moduleComponentName(input7.module) : "";
|
|
19786
|
+
const serviceRef = lowerlize(moduleClassName);
|
|
19787
|
+
const name = input7.mutation;
|
|
19788
|
+
return await this.#writeServiceSignalEntry(workspace, {
|
|
19789
|
+
command: "add-mutation",
|
|
19790
|
+
app: input7.app,
|
|
19791
|
+
module: input7.module,
|
|
19792
|
+
entryKind: "mutation",
|
|
19793
|
+
entryName: name,
|
|
19794
|
+
requiredInput: "mutation",
|
|
19795
|
+
serviceMethod: name ? {
|
|
19796
|
+
name,
|
|
19797
|
+
block: [
|
|
19798
|
+
` async ${name}() {`,
|
|
19799
|
+
` // TODO(service): implement ${moduleClassName}Service.${name}`,
|
|
19800
|
+
` return true;`,
|
|
19801
|
+
` }`
|
|
19802
|
+
].join(`
|
|
19803
|
+
`)
|
|
19804
|
+
} : null,
|
|
19805
|
+
signal: name ? {
|
|
19806
|
+
className: `${moduleClassName}Endpoint`,
|
|
19807
|
+
entryLine: [
|
|
19808
|
+
`${name}: mutation(Boolean)`,
|
|
19809
|
+
` .exec(async function () {`,
|
|
19810
|
+
` return await this.${serviceRef}Service.${name}();`,
|
|
19811
|
+
` }),`
|
|
19812
|
+
].join(`
|
|
19813
|
+
`),
|
|
19814
|
+
param: { mode: "destructure", name: "mutation" }
|
|
19815
|
+
} : null
|
|
19816
|
+
});
|
|
19817
|
+
}
|
|
19818
|
+
async addSlice(workspace, input7) {
|
|
19819
|
+
const moduleClassName = input7.module ? moduleComponentName(input7.module) : "";
|
|
19820
|
+
const serviceRef = lowerlize(moduleClassName);
|
|
19821
|
+
const name = input7.slice;
|
|
19822
|
+
const queryName = name ? `query${capitalize12(name)}` : null;
|
|
19823
|
+
return await this.#writeServiceSignalEntry(workspace, {
|
|
19824
|
+
command: "add-slice",
|
|
19825
|
+
app: input7.app,
|
|
19826
|
+
module: input7.module,
|
|
19827
|
+
entryKind: "slice",
|
|
19828
|
+
entryName: name,
|
|
19829
|
+
requiredInput: "slice",
|
|
19830
|
+
serviceMethod: name && queryName ? {
|
|
19831
|
+
name: queryName,
|
|
19832
|
+
block: [
|
|
19833
|
+
` ${queryName}() {`,
|
|
19834
|
+
` // TODO(service): return a QueryOf for the ${name} slice`,
|
|
19835
|
+
` return {};`,
|
|
19836
|
+
` }`
|
|
19837
|
+
].join(`
|
|
19838
|
+
`)
|
|
19839
|
+
} : null,
|
|
19840
|
+
signal: name && queryName ? {
|
|
19841
|
+
className: `${moduleClassName}Slice`,
|
|
19842
|
+
entryLine: [
|
|
19843
|
+
`${name}: init()`,
|
|
19844
|
+
` .exec(function () {`,
|
|
19845
|
+
` return this.${serviceRef}Service.${queryName}();`,
|
|
19846
|
+
` }),`
|
|
19847
|
+
].join(`
|
|
19848
|
+
`),
|
|
19849
|
+
param: { mode: "positional", name: "init" }
|
|
19850
|
+
} : null
|
|
19851
|
+
});
|
|
19852
|
+
}
|
|
19853
|
+
async#writeServiceSignalEntry(workspace, spec) {
|
|
19854
|
+
const sys3 = await this.resolveSys(workspace, spec.app);
|
|
19855
|
+
const diagnostics = compactDiagnostics([
|
|
19856
|
+
!sys3 && { severity: "error", code: "primitive-target-missing", message: "Target app or library was not found." },
|
|
19857
|
+
!spec.module && {
|
|
19858
|
+
severity: "error",
|
|
19859
|
+
code: "primitive-input-missing",
|
|
19860
|
+
message: "Module is required.",
|
|
19861
|
+
input: "module"
|
|
19862
|
+
},
|
|
19863
|
+
!spec.entryName && {
|
|
19864
|
+
severity: "error",
|
|
19865
|
+
code: "primitive-input-missing",
|
|
19866
|
+
message: `${capitalize12(spec.requiredInput)} name is required.`,
|
|
19867
|
+
input: spec.requiredInput
|
|
19868
|
+
}
|
|
19869
|
+
]);
|
|
19870
|
+
if (!sys3 || !spec.module || !spec.entryName || !spec.serviceMethod || !spec.signal) {
|
|
19871
|
+
return createPrimitiveWriteReport({
|
|
19872
|
+
command: spec.command,
|
|
19873
|
+
changedFiles: [],
|
|
19874
|
+
generatedFiles: [],
|
|
19875
|
+
validationCommands: [],
|
|
19876
|
+
diagnostics,
|
|
19877
|
+
nextActions: []
|
|
19878
|
+
});
|
|
19879
|
+
}
|
|
19880
|
+
const paths = moduleSourcePaths(spec.module);
|
|
19881
|
+
const servicePath = paths.service;
|
|
19882
|
+
const signalPath = paths.signal;
|
|
19883
|
+
const changedFiles = [];
|
|
19884
|
+
const generatedFiles2 = generatedFilesForSync(sys3);
|
|
19885
|
+
const [hasServiceFile, hasSignalFile] = await Promise.all([sys3.exists(servicePath), sys3.exists(signalPath)]);
|
|
19886
|
+
if (!hasServiceFile) {
|
|
19887
|
+
diagnostics.push({
|
|
19888
|
+
severity: "error",
|
|
19889
|
+
code: "primitive-source-missing",
|
|
19890
|
+
message: `Service source file was not found: ${servicePath}.`
|
|
19891
|
+
});
|
|
19892
|
+
}
|
|
19893
|
+
if (!hasSignalFile) {
|
|
19894
|
+
diagnostics.push({
|
|
19895
|
+
severity: "error",
|
|
19896
|
+
code: "primitive-source-missing",
|
|
19897
|
+
message: `Signal source file was not found: ${signalPath}.`
|
|
19898
|
+
});
|
|
19899
|
+
}
|
|
19900
|
+
if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
19901
|
+
return createPrimitiveWriteReport({
|
|
19902
|
+
command: spec.command,
|
|
19903
|
+
changedFiles,
|
|
19904
|
+
generatedFiles: generatedFiles2,
|
|
19905
|
+
validationCommands: validationCommandsForTarget(sys3.name),
|
|
19906
|
+
diagnostics,
|
|
19907
|
+
nextActions: nextActionsForTarget(sys3.name)
|
|
19908
|
+
});
|
|
19909
|
+
}
|
|
19910
|
+
const serviceClassName = `${moduleComponentName(spec.module)}Service`;
|
|
19911
|
+
const serviceContent = await sys3.readFile(servicePath);
|
|
19912
|
+
const signalContent = await sys3.readFile(signalPath);
|
|
19913
|
+
const serviceMethodExists = hasClassMethod(serviceContent, serviceClassName, spec.serviceMethod.name);
|
|
19914
|
+
if (serviceMethodExists) {
|
|
19915
|
+
diagnostics.push({
|
|
19916
|
+
severity: "error",
|
|
19917
|
+
code: "primitive-service-method-exists",
|
|
19918
|
+
input: spec.requiredInput,
|
|
19919
|
+
message: `Method "${spec.serviceMethod.name}" already exists in ${serviceClassName}.`
|
|
19920
|
+
});
|
|
19921
|
+
}
|
|
19922
|
+
if (hasSignalFactoryEntry(signalContent, spec.signal.className, spec.entryName)) {
|
|
19923
|
+
diagnostics.push({
|
|
19924
|
+
severity: "error",
|
|
19925
|
+
code: "primitive-signal-entry-exists",
|
|
19926
|
+
input: spec.requiredInput,
|
|
19927
|
+
message: `Entry "${spec.entryName}" already exists in ${spec.signal.className}.`
|
|
19928
|
+
});
|
|
19929
|
+
}
|
|
19930
|
+
const nextServiceContent = serviceMethodExists ? serviceContent : insertClassMethod(serviceContent, serviceClassName, spec.serviceMethod.block);
|
|
19931
|
+
const nextSignalContent = insertSignalFactoryEntry(signalContent, spec.signal.className, spec.entryName, spec.signal.entryLine, spec.signal.param);
|
|
19932
|
+
if (!nextServiceContent) {
|
|
19933
|
+
diagnostics.push({
|
|
19934
|
+
severity: "error",
|
|
19935
|
+
code: "primitive-service-shape-unsupported",
|
|
19936
|
+
message: `Could not find ${serviceClassName} class body in ${servicePath}.`
|
|
19937
|
+
});
|
|
19938
|
+
}
|
|
19939
|
+
if (!nextSignalContent) {
|
|
19940
|
+
diagnostics.push({
|
|
19941
|
+
severity: "error",
|
|
19942
|
+
code: "primitive-signal-shape-unsupported",
|
|
19943
|
+
message: `Could not find a safe insertion point in ${spec.signal.className} within ${signalPath}. Ensure the class exists and its factory returns an object literal.`
|
|
19944
|
+
});
|
|
19945
|
+
}
|
|
19946
|
+
if (nextServiceContent && hasSourceParseErrors(nextServiceContent, "service.ts")) {
|
|
19947
|
+
diagnostics.push({
|
|
19948
|
+
severity: "error",
|
|
19949
|
+
code: "primitive-post-edit-service-parse-failed",
|
|
19950
|
+
failureScope: "source-change",
|
|
19951
|
+
message: `Edited ${servicePath} did not parse cleanly; refusing to write source.`
|
|
19952
|
+
});
|
|
19953
|
+
}
|
|
19954
|
+
if (nextSignalContent && hasSourceParseErrors(nextSignalContent, "signal.ts")) {
|
|
19955
|
+
diagnostics.push({
|
|
19956
|
+
severity: "error",
|
|
19957
|
+
code: "primitive-post-edit-signal-parse-failed",
|
|
19958
|
+
failureScope: "source-change",
|
|
19959
|
+
message: `Edited ${signalPath} did not parse cleanly; refusing to write source.`
|
|
19960
|
+
});
|
|
19961
|
+
}
|
|
19962
|
+
if (nextSignalContent && !hasSignalFactoryEntry(nextSignalContent, spec.signal.className, spec.entryName)) {
|
|
19963
|
+
diagnostics.push({
|
|
19964
|
+
severity: "error",
|
|
19965
|
+
code: "primitive-post-edit-signal-verify-failed",
|
|
19966
|
+
failureScope: "source-change",
|
|
19967
|
+
message: `Edited ${signalPath} did not contain entry "${spec.entryName}" in ${spec.signal.className}.`
|
|
19968
|
+
});
|
|
19969
|
+
}
|
|
19970
|
+
if (!diagnostics.some((diagnostic) => diagnostic.severity === "error") && nextServiceContent && nextSignalContent) {
|
|
19971
|
+
await sys3.writeFile(servicePath, nextServiceContent);
|
|
19972
|
+
await sys3.writeFile(signalPath, nextSignalContent);
|
|
19973
|
+
changedFiles.push(sourceFile(sys3, servicePath, "modify", `Service ${spec.entryKind} was added.`), sourceFile(sys3, signalPath, "modify", `Signal ${spec.entryKind} was added.`));
|
|
19974
|
+
}
|
|
19975
|
+
return createPrimitiveWriteReport({
|
|
19976
|
+
command: spec.command,
|
|
19977
|
+
changedFiles,
|
|
19978
|
+
generatedFiles: generatedFiles2,
|
|
19979
|
+
validationCommands: validationCommandsForTarget(sys3.name),
|
|
19980
|
+
diagnostics,
|
|
19981
|
+
nextActions: nextActionsForTarget(sys3.name)
|
|
19982
|
+
});
|
|
19983
|
+
}
|
|
19587
19984
|
}
|
|
19588
19985
|
|
|
19589
19986
|
// pkgs/@akanjs/cli/scalar/scalar.prompt.ts
|
|
@@ -19801,7 +20198,9 @@ var createCliWorkflowStepRegistry = (workspace) => createWorkflowStepRegistry({
|
|
|
19801
20198
|
createScalar: (sys3, scalar) => CommandContainer.get(ScalarScript).createScalar(sys3, scalar),
|
|
19802
20199
|
createUi: (input8) => CommandContainer.get(PrimitiveScript).createUi(workspace, input8),
|
|
19803
20200
|
addField: (input8) => CommandContainer.get(PrimitiveScript).addField(workspace, input8),
|
|
19804
|
-
addEnumField: (input8) => CommandContainer.get(PrimitiveScript).addEnumField(workspace, input8)
|
|
20201
|
+
addEnumField: (input8) => CommandContainer.get(PrimitiveScript).addEnumField(workspace, input8),
|
|
20202
|
+
addMutation: (input8) => CommandContainer.get(PrimitiveScript).addMutation(workspace, input8),
|
|
20203
|
+
addSlice: (input8) => CommandContainer.get(PrimitiveScript).addSlice(workspace, input8)
|
|
19805
20204
|
});
|
|
19806
20205
|
|
|
19807
20206
|
// pkgs/@akanjs/cli/context/context.runner.ts
|
|
@@ -20992,7 +21391,9 @@ class WorkflowScript extends script("workflow", [WorkflowRunner, ModuleScript, S
|
|
|
20992
21391
|
createScalar: (sys3, scalar) => this.scalarScript.createScalar(sys3, scalar),
|
|
20993
21392
|
createUi: (input8) => this.primitiveScript.createUi(workspace, input8),
|
|
20994
21393
|
addField: (input8) => this.primitiveScript.addField(workspace, input8),
|
|
20995
|
-
addEnumField: (input8) => this.primitiveScript.addEnumField(workspace, input8)
|
|
21394
|
+
addEnumField: (input8) => this.primitiveScript.addEnumField(workspace, input8),
|
|
21395
|
+
addMutation: (input8) => this.primitiveScript.addMutation(workspace, input8),
|
|
21396
|
+
addSlice: (input8) => this.primitiveScript.addSlice(workspace, input8)
|
|
20996
21397
|
})
|
|
20997
21398
|
}));
|
|
20998
21399
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "2.3.11-rc.
|
|
3
|
+
"version": "2.3.11-rc.4",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@langchain/openai": "^1.4.6",
|
|
35
35
|
"@tailwindcss/node": "^4.3.0",
|
|
36
36
|
"@trapezedev/project": "^7.1.4",
|
|
37
|
-
"akanjs": "2.3.11-rc.
|
|
37
|
+
"akanjs": "2.3.11-rc.4",
|
|
38
38
|
"chalk": "^5.6.2",
|
|
39
39
|
"commander": "^14.0.3",
|
|
40
40
|
"daisyui": "5.5.23",
|