@kody-ade/kody-engine 0.4.321 → 0.4.323
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/bin/kody.js +410 -70
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.323",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -3942,6 +3942,73 @@ var init_capabilityReport = __esm({
|
|
|
3942
3942
|
}
|
|
3943
3943
|
});
|
|
3944
3944
|
|
|
3945
|
+
// src/goal/evidenceState.ts
|
|
3946
|
+
function parseGoalEvidenceState(raw) {
|
|
3947
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
3948
|
+
const out = {};
|
|
3949
|
+
for (const [evidence, value] of Object.entries(raw)) {
|
|
3950
|
+
const progress = parseGoalEvidenceProgress(value);
|
|
3951
|
+
if (progress) out[evidence] = progress;
|
|
3952
|
+
}
|
|
3953
|
+
return out;
|
|
3954
|
+
}
|
|
3955
|
+
function mergeGoalEvidenceProgress(state, evidence, update) {
|
|
3956
|
+
const prior = state[evidence];
|
|
3957
|
+
const next = {
|
|
3958
|
+
resultClass: update.resultClass,
|
|
3959
|
+
attempts: update.attempts ?? prior?.attempts ?? 0,
|
|
3960
|
+
...prior?.reason ? { reason: prior.reason } : {},
|
|
3961
|
+
...prior?.nextAction ? { nextAction: prior.nextAction } : {},
|
|
3962
|
+
...prior?.nextRetryAt ? { nextRetryAt: prior.nextRetryAt } : {},
|
|
3963
|
+
...prior?.issue ? { issue: prior.issue } : {},
|
|
3964
|
+
...prior?.updatedAt ? { updatedAt: prior.updatedAt } : {},
|
|
3965
|
+
...definedProgressFields(update)
|
|
3966
|
+
};
|
|
3967
|
+
return {
|
|
3968
|
+
...state,
|
|
3969
|
+
[evidence]: next
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
function isGoalEvidenceResultClass(value) {
|
|
3973
|
+
return value === "succeeded" || value === "pending" || value === "retryable" || value === "needsFix" || value === "fatal";
|
|
3974
|
+
}
|
|
3975
|
+
function parseGoalEvidenceProgress(value) {
|
|
3976
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
3977
|
+
const raw = value;
|
|
3978
|
+
if (!isGoalEvidenceResultClass(raw.resultClass)) return null;
|
|
3979
|
+
const attempts = typeof raw.attempts === "number" && raw.attempts >= 0 ? Math.floor(raw.attempts) : 0;
|
|
3980
|
+
return {
|
|
3981
|
+
resultClass: raw.resultClass,
|
|
3982
|
+
attempts,
|
|
3983
|
+
...stringField2(raw.reason) ? { reason: stringField2(raw.reason) } : {},
|
|
3984
|
+
...stringField2(raw.nextAction) ? { nextAction: stringField2(raw.nextAction) } : {},
|
|
3985
|
+
...stringField2(raw.nextRetryAt) ? { nextRetryAt: stringField2(raw.nextRetryAt) } : {},
|
|
3986
|
+
...positiveInteger(raw.issue) ? { issue: positiveInteger(raw.issue) } : {},
|
|
3987
|
+
...stringField2(raw.updatedAt) ? { updatedAt: stringField2(raw.updatedAt) } : {}
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
function definedProgressFields(update) {
|
|
3991
|
+
const out = {};
|
|
3992
|
+
if (update.reason !== void 0) out.reason = update.reason;
|
|
3993
|
+
if (update.nextAction !== void 0) out.nextAction = update.nextAction;
|
|
3994
|
+
if (update.nextRetryAt !== void 0) out.nextRetryAt = update.nextRetryAt;
|
|
3995
|
+
if (update.issue !== void 0) out.issue = update.issue;
|
|
3996
|
+
if (update.updatedAt !== void 0) out.updatedAt = update.updatedAt;
|
|
3997
|
+
return out;
|
|
3998
|
+
}
|
|
3999
|
+
function stringField2(value) {
|
|
4000
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
4001
|
+
}
|
|
4002
|
+
function positiveInteger(value) {
|
|
4003
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) return value;
|
|
4004
|
+
return void 0;
|
|
4005
|
+
}
|
|
4006
|
+
var init_evidenceState = __esm({
|
|
4007
|
+
"src/goal/evidenceState.ts"() {
|
|
4008
|
+
"use strict";
|
|
4009
|
+
}
|
|
4010
|
+
});
|
|
4011
|
+
|
|
3945
4012
|
// src/capabilityResult.ts
|
|
3946
4013
|
function parseCapabilityResultsFromText(text) {
|
|
3947
4014
|
const results = [];
|
|
@@ -3979,6 +4046,7 @@ function parseCapabilityResult(raw) {
|
|
|
3979
4046
|
version: 1,
|
|
3980
4047
|
...target ? { target } : {},
|
|
3981
4048
|
status: obj.status,
|
|
4049
|
+
...isGoalEvidenceResultClass(obj.resultClass) ? { resultClass: obj.resultClass } : {},
|
|
3982
4050
|
summary,
|
|
3983
4051
|
...evidence ? { evidence } : {},
|
|
3984
4052
|
facts,
|
|
@@ -4038,6 +4106,7 @@ var init_capabilityResult = __esm({
|
|
|
4038
4106
|
"src/capabilityResult.ts"() {
|
|
4039
4107
|
"use strict";
|
|
4040
4108
|
init_capabilityReport();
|
|
4109
|
+
init_evidenceState();
|
|
4041
4110
|
RESULT_LINE = /^KODY_(?:CAPABILITY|CAPABILITY)_RESULT=(.+)$/gm;
|
|
4042
4111
|
STATUSES = /* @__PURE__ */ new Set(["pass", "fail", "blocked", "changed", "noop"]);
|
|
4043
4112
|
CONTROL_FACT_KEYS2 = /* @__PURE__ */ new Set(["blockers", "destination", "capabilities", "route", "stage", "state"]);
|
|
@@ -6831,6 +6900,8 @@ function planManagedGoalTick(goal) {
|
|
|
6831
6900
|
if (!missing) {
|
|
6832
6901
|
goal.stage = "done";
|
|
6833
6902
|
delete goal.facts.pendingEvidence;
|
|
6903
|
+
goal.reason = "destination evidence satisfied";
|
|
6904
|
+
goal.nextAction = "done";
|
|
6834
6905
|
return { kind: "done" };
|
|
6835
6906
|
}
|
|
6836
6907
|
const step = goal.route.find((candidate) => candidate.evidence === missing);
|
|
@@ -6840,32 +6911,44 @@ function planManagedGoalTick(goal) {
|
|
|
6840
6911
|
delete goal.facts.pendingEvidence;
|
|
6841
6912
|
const total = typeof goal.facts.simpleAttachedTaskCount === "number" ? goal.facts.simpleAttachedTaskCount : 0;
|
|
6842
6913
|
const open = typeof goal.facts.simpleOpenTaskCount === "number" ? goal.facts.simpleOpenTaskCount : 0;
|
|
6914
|
+
goal.reason = total === 0 ? "waiting for labelled tasks" : `waiting for ${open} open labelled task(s)`;
|
|
6915
|
+
goal.nextAction = "wait";
|
|
6843
6916
|
return {
|
|
6844
6917
|
kind: "wait",
|
|
6845
6918
|
evidence: missing,
|
|
6846
6919
|
stage: "waiting",
|
|
6847
|
-
reason:
|
|
6920
|
+
reason: goal.reason
|
|
6848
6921
|
};
|
|
6849
6922
|
}
|
|
6850
6923
|
const reason = `no route step for evidence: ${missing}`;
|
|
6851
6924
|
goal.stage = "blocked";
|
|
6925
|
+
goal.reason = reason;
|
|
6926
|
+
goal.nextAction = "fix route";
|
|
6852
6927
|
pushBlocker(goal, reason);
|
|
6853
6928
|
return { kind: "blocked", evidence: missing, stage: "blocked", reason };
|
|
6854
6929
|
}
|
|
6930
|
+
const progressDecision = decisionFromEvidenceProgress(goal, step, missing);
|
|
6931
|
+
if (progressDecision) return progressDecision;
|
|
6855
6932
|
if (!goal.capabilities.includes(step.capability)) {
|
|
6856
6933
|
const reason = `route capability ${step.capability} is not attached to this goal`;
|
|
6857
6934
|
goal.stage = "blocked";
|
|
6935
|
+
goal.reason = reason;
|
|
6936
|
+
goal.nextAction = "attach capability";
|
|
6858
6937
|
pushBlocker(goal, reason);
|
|
6859
6938
|
return { kind: "blocked", evidence: missing, stage: step.stage, reason };
|
|
6860
6939
|
}
|
|
6861
6940
|
const resolved = resolveRouteArgs(goal, step);
|
|
6862
6941
|
if (!resolved.ok) {
|
|
6863
6942
|
goal.stage = "blocked";
|
|
6943
|
+
goal.reason = resolved.reason;
|
|
6944
|
+
goal.nextAction = "fix route args";
|
|
6864
6945
|
pushBlocker(goal, resolved.reason);
|
|
6865
6946
|
return { kind: "blocked", evidence: missing, stage: step.stage, reason: resolved.reason };
|
|
6866
6947
|
}
|
|
6867
6948
|
goal.stage = step.stage;
|
|
6868
6949
|
goal.facts.pendingEvidence = missing;
|
|
6950
|
+
goal.reason = `dispatch ${step.capability} for ${missing}`;
|
|
6951
|
+
goal.nextAction = "dispatch";
|
|
6869
6952
|
return {
|
|
6870
6953
|
kind: "dispatch",
|
|
6871
6954
|
evidence: missing,
|
|
@@ -6876,6 +6959,79 @@ function planManagedGoalTick(goal) {
|
|
|
6876
6959
|
...step.saveReport === true ? { saveReport: true } : {}
|
|
6877
6960
|
};
|
|
6878
6961
|
}
|
|
6962
|
+
function decisionFromEvidenceProgress(goal, step, evidence) {
|
|
6963
|
+
const progress = goal.evidenceState?.[evidence];
|
|
6964
|
+
if (!progress) return null;
|
|
6965
|
+
if (progress.resultClass === "pending") {
|
|
6966
|
+
const policy = step.onPending ?? { action: "wait" };
|
|
6967
|
+
if (policy.action === "retry") return null;
|
|
6968
|
+
if (policy.action === "block" || policy.action === "issue") {
|
|
6969
|
+
const reason2 = progress.reason ?? `waiting for ${evidence}`;
|
|
6970
|
+
goal.stage = "blocked";
|
|
6971
|
+
goal.reason = reason2;
|
|
6972
|
+
goal.nextAction = policy.action === "issue" ? "create issue" : "block";
|
|
6973
|
+
pushBlocker(goal, reason2);
|
|
6974
|
+
return { kind: "blocked", evidence, stage: step.stage, reason: reason2 };
|
|
6975
|
+
}
|
|
6976
|
+
const reason = progress.reason ?? `waiting for ${evidence}`;
|
|
6977
|
+
goal.stage = step.stage;
|
|
6978
|
+
goal.reason = reason;
|
|
6979
|
+
goal.nextAction = progress.nextAction ?? "wait";
|
|
6980
|
+
return { kind: "wait", evidence, stage: step.stage, reason };
|
|
6981
|
+
}
|
|
6982
|
+
if (progress.resultClass === "retryable") {
|
|
6983
|
+
const policy = step.onFailure ?? { action: "retry" };
|
|
6984
|
+
if (policy.action === "block" || policy.action === "issue") {
|
|
6985
|
+
const reason = progress.reason ?? `retryable failure for ${evidence}`;
|
|
6986
|
+
goal.stage = "blocked";
|
|
6987
|
+
goal.reason = reason;
|
|
6988
|
+
goal.nextAction = policy.action === "issue" ? "create issue" : "block";
|
|
6989
|
+
pushBlocker(goal, reason);
|
|
6990
|
+
return { kind: "blocked", evidence, stage: step.stage, reason };
|
|
6991
|
+
}
|
|
6992
|
+
if (policy.action === "wait") {
|
|
6993
|
+
const reason = progress.reason ?? `waiting to retry ${evidence}`;
|
|
6994
|
+
goal.stage = step.stage;
|
|
6995
|
+
goal.reason = reason;
|
|
6996
|
+
goal.nextAction = progress.nextRetryAt ? `retry after ${progress.nextRetryAt}` : "wait";
|
|
6997
|
+
return { kind: "wait", evidence, stage: step.stage, reason };
|
|
6998
|
+
}
|
|
6999
|
+
if (policy.maxAttempts !== void 0 && progress.attempts >= policy.maxAttempts) {
|
|
7000
|
+
const reason = `retry limit reached for ${evidence}`;
|
|
7001
|
+
goal.stage = "blocked";
|
|
7002
|
+
goal.reason = reason;
|
|
7003
|
+
goal.nextAction = "create issue";
|
|
7004
|
+
pushBlocker(goal, reason);
|
|
7005
|
+
return { kind: "blocked", evidence, stage: step.stage, reason };
|
|
7006
|
+
}
|
|
7007
|
+
if (progress.nextRetryAt && Date.parse(progress.nextRetryAt) > Date.now()) {
|
|
7008
|
+
const reason = progress.reason ?? `retry ${evidence} after ${progress.nextRetryAt}`;
|
|
7009
|
+
goal.stage = step.stage;
|
|
7010
|
+
goal.reason = reason;
|
|
7011
|
+
goal.nextAction = `retry after ${progress.nextRetryAt}`;
|
|
7012
|
+
return { kind: "wait", evidence, stage: step.stage, reason };
|
|
7013
|
+
}
|
|
7014
|
+
return null;
|
|
7015
|
+
}
|
|
7016
|
+
if (progress.resultClass === "needsFix" || progress.resultClass === "fatal") {
|
|
7017
|
+
const policy = step.onFailure ?? defaultFailurePolicy(progress.resultClass);
|
|
7018
|
+
if (policy.action === "retry") return null;
|
|
7019
|
+
const reason = progress.reason ?? `${resultClassLabel(progress.resultClass)} for ${evidence}`;
|
|
7020
|
+
goal.stage = "blocked";
|
|
7021
|
+
goal.reason = reason;
|
|
7022
|
+
goal.nextAction = progress.issue ? `fix issue #${progress.issue}` : policy.action === "issue" ? "create issue" : "block";
|
|
7023
|
+
pushBlocker(goal, reason);
|
|
7024
|
+
return { kind: "blocked", evidence, stage: step.stage, reason };
|
|
7025
|
+
}
|
|
7026
|
+
return null;
|
|
7027
|
+
}
|
|
7028
|
+
function defaultFailurePolicy(resultClass) {
|
|
7029
|
+
return resultClass === "needsFix" ? { action: "issue" } : { action: "block" };
|
|
7030
|
+
}
|
|
7031
|
+
function resultClassLabel(resultClass) {
|
|
7032
|
+
if (resultClass === "needsFix") return "needs fix";
|
|
7033
|
+
return resultClass;
|
|
7034
|
+
}
|
|
6879
7035
|
function asStringArray(value) {
|
|
6880
7036
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) return null;
|
|
6881
7037
|
return [...value];
|
|
@@ -6901,11 +7057,30 @@ function asRoute(value) {
|
|
|
6901
7057
|
capability: raw.capability,
|
|
6902
7058
|
executable: typeof raw.executable === "string" ? raw.executable : void 0,
|
|
6903
7059
|
args: args ?? void 0,
|
|
6904
|
-
saveReport: raw.saveReport === true
|
|
7060
|
+
saveReport: raw.saveReport === true,
|
|
7061
|
+
onPending: asRoutePolicy(raw.onPending),
|
|
7062
|
+
onFailure: asRoutePolicy(raw.onFailure)
|
|
6905
7063
|
});
|
|
6906
7064
|
}
|
|
6907
7065
|
return route;
|
|
6908
7066
|
}
|
|
7067
|
+
function asRoutePolicy(value) {
|
|
7068
|
+
if (typeof value === "string") {
|
|
7069
|
+
return isRoutePolicyAction(value) ? { action: value } : void 0;
|
|
7070
|
+
}
|
|
7071
|
+
const raw = asRecord(value);
|
|
7072
|
+
if (!raw || !isRoutePolicyAction(raw.action)) return void 0;
|
|
7073
|
+
const maxAttempts = typeof raw.maxAttempts === "number" && Number.isInteger(raw.maxAttempts) && raw.maxAttempts > 0 ? raw.maxAttempts : void 0;
|
|
7074
|
+
const retryAfterSeconds = typeof raw.retryAfterSeconds === "number" && raw.retryAfterSeconds >= 0 ? Math.floor(raw.retryAfterSeconds) : void 0;
|
|
7075
|
+
return {
|
|
7076
|
+
action: raw.action,
|
|
7077
|
+
...maxAttempts !== void 0 ? { maxAttempts } : {},
|
|
7078
|
+
...retryAfterSeconds !== void 0 ? { retryAfterSeconds } : {}
|
|
7079
|
+
};
|
|
7080
|
+
}
|
|
7081
|
+
function isRoutePolicyAction(value) {
|
|
7082
|
+
return value === "wait" || value === "retry" || value === "block" || value === "issue";
|
|
7083
|
+
}
|
|
6909
7084
|
function asPreferredRunTime(value) {
|
|
6910
7085
|
const raw = asRecord(value);
|
|
6911
7086
|
if (!raw) return void 0;
|
|
@@ -6941,7 +7116,10 @@ function managedGoalFromState(state) {
|
|
|
6941
7116
|
loopTarget: asLoopTarget(extra.loopTarget),
|
|
6942
7117
|
stage: typeof extra.stage === "string" ? extra.stage : void 0,
|
|
6943
7118
|
facts,
|
|
6944
|
-
blockers
|
|
7119
|
+
blockers,
|
|
7120
|
+
evidenceState: parseGoalEvidenceState(extra.evidenceState),
|
|
7121
|
+
reason: typeof extra.reason === "string" ? extra.reason : void 0,
|
|
7122
|
+
nextAction: typeof extra.nextAction === "string" ? extra.nextAction : void 0
|
|
6945
7123
|
};
|
|
6946
7124
|
}
|
|
6947
7125
|
function writeManagedGoalToState(state, goal) {
|
|
@@ -6955,7 +7133,10 @@ function writeManagedGoalToState(state, goal) {
|
|
|
6955
7133
|
route: goal.route,
|
|
6956
7134
|
stage: goal.stage,
|
|
6957
7135
|
facts: goal.facts,
|
|
6958
|
-
blockers: goal.blockers
|
|
7136
|
+
blockers: goal.blockers,
|
|
7137
|
+
evidenceState: goal.evidenceState ?? {},
|
|
7138
|
+
reason: goal.reason,
|
|
7139
|
+
nextAction: goal.nextAction
|
|
6959
7140
|
}
|
|
6960
7141
|
};
|
|
6961
7142
|
}
|
|
@@ -6963,6 +7144,7 @@ var SIMPLE_GOAL_TYPE, SIMPLE_GOAL_EVIDENCE;
|
|
|
6963
7144
|
var init_manager = __esm({
|
|
6964
7145
|
"src/goal/manager.ts"() {
|
|
6965
7146
|
"use strict";
|
|
7147
|
+
init_evidenceState();
|
|
6966
7148
|
SIMPLE_GOAL_TYPE = "simple";
|
|
6967
7149
|
SIMPLE_GOAL_EVIDENCE = "labelledTasksComplete";
|
|
6968
7150
|
}
|
|
@@ -7072,7 +7254,8 @@ function goalRunLogSnapshot(goalId, goalState, goal) {
|
|
|
7072
7254
|
preferredRunTime: goal.preferredRunTime,
|
|
7073
7255
|
loopTarget: goal.loopTarget,
|
|
7074
7256
|
blockers: [...goal.blockers],
|
|
7075
|
-
facts: { ...goal.facts }
|
|
7257
|
+
facts: { ...goal.facts },
|
|
7258
|
+
evidenceState: { ...goal.evidenceState ?? {} }
|
|
7076
7259
|
};
|
|
7077
7260
|
}
|
|
7078
7261
|
function goalRunLogChange(before, after) {
|
|
@@ -7096,6 +7279,11 @@ function goalRunLogChange(before, after) {
|
|
|
7096
7279
|
const evidence = diffStringArrays(beforeSatisfied ?? [], afterSatisfied ?? []);
|
|
7097
7280
|
if (evidence.added.length > 0 || evidence.removed.length > 0) change.satisfiedEvidence = evidence;
|
|
7098
7281
|
}
|
|
7282
|
+
const beforeEvidenceState = recordValue2(before.evidenceState);
|
|
7283
|
+
const afterEvidenceState = recordValue2(after.evidenceState);
|
|
7284
|
+
if (beforeEvidenceState || afterEvidenceState) {
|
|
7285
|
+
change.evidenceState = diffRecordKeys(beforeEvidenceState ?? {}, afterEvidenceState ?? {});
|
|
7286
|
+
}
|
|
7099
7287
|
return Object.keys(change).length > 0 ? change : void 0;
|
|
7100
7288
|
}
|
|
7101
7289
|
function goalRunLogs(data) {
|
|
@@ -7456,11 +7644,11 @@ function parseTodoGoalState(goalId, filePath, raw) {
|
|
|
7456
7644
|
const data = parseJsonRecord(raw) ?? {};
|
|
7457
7645
|
const items = normalizeItems(data.items);
|
|
7458
7646
|
const destination = recordField(data.destination);
|
|
7459
|
-
const evidence = stringArray(destination.evidence).length > 0 ? stringArray(destination.evidence) : stringArray(data.evidence).length > 0 ? stringArray(data.evidence) : items.map((item) =>
|
|
7647
|
+
const evidence = stringArray(destination.evidence).length > 0 ? stringArray(destination.evidence) : stringArray(data.evidence).length > 0 ? stringArray(data.evidence) : items.map((item) => stringField3(recordField(item.meta).evidence) || item.id).filter(Boolean);
|
|
7460
7648
|
const facts = {
|
|
7461
7649
|
...recordField(data.facts),
|
|
7462
7650
|
...Object.fromEntries(
|
|
7463
|
-
items.map((item) => [
|
|
7651
|
+
items.map((item) => [stringField3(recordField(item.meta).evidence) || item.id, item.completed])
|
|
7464
7652
|
)
|
|
7465
7653
|
};
|
|
7466
7654
|
const route = Array.isArray(data.route) ? data.route : routeFromItems(items);
|
|
@@ -7472,10 +7660,10 @@ function parseTodoGoalState(goalId, filePath, raw) {
|
|
|
7472
7660
|
type: data.type ?? "general",
|
|
7473
7661
|
destination: {
|
|
7474
7662
|
...destination,
|
|
7475
|
-
outcome:
|
|
7663
|
+
outcome: stringField3(data.description) || stringField3(destination.outcome),
|
|
7476
7664
|
evidence
|
|
7477
7665
|
},
|
|
7478
|
-
capabilities: stringArray(data.capabilities).length > 0 ? stringArray(data.capabilities) : route.map((step) =>
|
|
7666
|
+
capabilities: stringArray(data.capabilities).length > 0 ? stringArray(data.capabilities) : route.map((step) => stringField3(step.capability)).filter(Boolean),
|
|
7479
7667
|
route,
|
|
7480
7668
|
facts,
|
|
7481
7669
|
blockers: stringArray(data.blockers)
|
|
@@ -7487,16 +7675,25 @@ function isManagedTodoRaw(raw) {
|
|
|
7487
7675
|
function serializeTodoGoalState(goalId, state, previousRaw) {
|
|
7488
7676
|
const raw = JSON.parse(serializeGoalState(state));
|
|
7489
7677
|
const destination = recordField(raw.destination);
|
|
7490
|
-
const outcome =
|
|
7678
|
+
const outcome = stringField3(raw.description) || stringField3(destination.outcome);
|
|
7491
7679
|
const evidence = stringArray(destination.evidence).length > 0 ? stringArray(destination.evidence) : stringArray(raw.evidence);
|
|
7492
7680
|
const route = Array.isArray(raw.route) ? raw.route : [];
|
|
7493
7681
|
const facts = recordField(raw.facts);
|
|
7682
|
+
const evidenceState = recordField(raw.evidenceState);
|
|
7494
7683
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7495
|
-
const createdAt =
|
|
7496
|
-
const routeByEvidence = new Map(route.map((step) => [
|
|
7684
|
+
const createdAt = stringField3(raw.createdAt) || stringField3(raw.startedAt) || now;
|
|
7685
|
+
const routeByEvidence = new Map(route.map((step) => [stringField3(step.evidence), step]));
|
|
7497
7686
|
const previousItems = new Map(parseItemsFromAnyRaw(previousRaw ?? "").map((item) => [item.id, item]));
|
|
7498
7687
|
const items = evidence.length > 0 ? evidence.map(
|
|
7499
|
-
(key) => itemFromEvidence(
|
|
7688
|
+
(key) => itemFromEvidence(
|
|
7689
|
+
key,
|
|
7690
|
+
routeByEvidence.get(key),
|
|
7691
|
+
facts,
|
|
7692
|
+
evidenceState,
|
|
7693
|
+
createdAt,
|
|
7694
|
+
now,
|
|
7695
|
+
previousItems.get(key)
|
|
7696
|
+
)
|
|
7500
7697
|
) : stringArray(raw.capabilities).map(
|
|
7501
7698
|
(capability) => itemFromCapability(capability, createdAt, previousItems.get(capability))
|
|
7502
7699
|
);
|
|
@@ -7521,11 +7718,12 @@ function serializeTodoGoalState(goalId, state, previousRaw) {
|
|
|
7521
7718
|
function isManagedTodoRecord(record2) {
|
|
7522
7719
|
return record2.managed === true || record2.managed === "true" || record2.managedModel === "agentGoal" || record2.managedModel === "agentLoop";
|
|
7523
7720
|
}
|
|
7524
|
-
function itemFromEvidence(evidence, step, facts, createdAt, now, prior) {
|
|
7721
|
+
function itemFromEvidence(evidence, step, facts, evidenceState, createdAt, now, prior) {
|
|
7525
7722
|
const completed = facts[evidence] === true;
|
|
7723
|
+
const progress = recordField(evidenceState[evidence]);
|
|
7526
7724
|
return {
|
|
7527
7725
|
id: evidence,
|
|
7528
|
-
title: (prior?.title ??
|
|
7726
|
+
title: (prior?.title ?? stringField3(step?.stage)) || evidence,
|
|
7529
7727
|
body: prior?.body ?? "",
|
|
7530
7728
|
assignee: prior?.assignee ?? null,
|
|
7531
7729
|
completed,
|
|
@@ -7534,11 +7732,19 @@ function itemFromEvidence(evidence, step, facts, createdAt, now, prior) {
|
|
|
7534
7732
|
meta: {
|
|
7535
7733
|
...prior?.meta ?? {},
|
|
7536
7734
|
evidence,
|
|
7735
|
+
...stringField3(progress?.resultClass) ? { resultClass: stringField3(progress?.resultClass) } : {},
|
|
7736
|
+
...typeof progress?.attempts === "number" ? { attempts: progress.attempts } : {},
|
|
7737
|
+
...stringField3(progress?.reason) ? { reason: stringField3(progress?.reason) } : {},
|
|
7738
|
+
...stringField3(progress?.nextAction) ? { nextAction: stringField3(progress?.nextAction) } : {},
|
|
7739
|
+
...stringField3(progress?.nextRetryAt) ? { nextRetryAt: stringField3(progress?.nextRetryAt) } : {},
|
|
7740
|
+
...typeof progress?.issue === "number" ? { issue: progress.issue } : {},
|
|
7537
7741
|
...step ? {
|
|
7538
|
-
stage:
|
|
7539
|
-
capability:
|
|
7742
|
+
stage: stringField3(step.stage),
|
|
7743
|
+
capability: stringField3(step.capability),
|
|
7540
7744
|
...step.args && typeof step.args === "object" ? { args: step.args } : {},
|
|
7541
|
-
...step.saveReport === true ? { saveReport: true } : {}
|
|
7745
|
+
...step.saveReport === true ? { saveReport: true } : {},
|
|
7746
|
+
...step.onPending && typeof step.onPending === "object" ? { onPending: step.onPending } : {},
|
|
7747
|
+
...step.onFailure && typeof step.onFailure === "object" ? { onFailure: step.onFailure } : {}
|
|
7542
7748
|
} : {}
|
|
7543
7749
|
}
|
|
7544
7750
|
};
|
|
@@ -7558,9 +7764,9 @@ function itemFromCapability(capability, createdAt, prior) {
|
|
|
7558
7764
|
function routeFromItems(items) {
|
|
7559
7765
|
return items.flatMap((item) => {
|
|
7560
7766
|
const meta = recordField(item.meta);
|
|
7561
|
-
const evidence =
|
|
7562
|
-
const stage =
|
|
7563
|
-
const capability =
|
|
7767
|
+
const evidence = stringField3(meta.evidence) || item.id;
|
|
7768
|
+
const stage = stringField3(meta.stage);
|
|
7769
|
+
const capability = stringField3(meta.capability);
|
|
7564
7770
|
if (!evidence || !stage || !capability) return [];
|
|
7565
7771
|
return [
|
|
7566
7772
|
{
|
|
@@ -7568,7 +7774,9 @@ function routeFromItems(items) {
|
|
|
7568
7774
|
stage,
|
|
7569
7775
|
capability,
|
|
7570
7776
|
...meta.args ? { args: meta.args } : {},
|
|
7571
|
-
...meta.saveReport === true ? { saveReport: true } : {}
|
|
7777
|
+
...meta.saveReport === true ? { saveReport: true } : {},
|
|
7778
|
+
...meta.onPending ? { onPending: meta.onPending } : {},
|
|
7779
|
+
...meta.onFailure ? { onFailure: meta.onFailure } : {}
|
|
7572
7780
|
}
|
|
7573
7781
|
];
|
|
7574
7782
|
});
|
|
@@ -7591,7 +7799,7 @@ function parseJsonRecord(raw) {
|
|
|
7591
7799
|
function recordField(value) {
|
|
7592
7800
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7593
7801
|
}
|
|
7594
|
-
function
|
|
7802
|
+
function stringField3(value) {
|
|
7595
7803
|
return typeof value === "string" ? value : "";
|
|
7596
7804
|
}
|
|
7597
7805
|
function stringArray(value) {
|
|
@@ -8431,7 +8639,9 @@ async function planGoalCapabilitySchedule(opts) {
|
|
|
8431
8639
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
8432
8640
|
const statuses = {};
|
|
8433
8641
|
const blockers = [];
|
|
8434
|
-
|
|
8642
|
+
const explicitCapabilityTarget = opts.goal.loopTarget?.type === "capability" ? opts.goal.loopTarget.id.trim() : "";
|
|
8643
|
+
const capabilitySlugs = explicitCapabilityTarget ? [explicitCapabilityTarget] : opts.goal.capabilities;
|
|
8644
|
+
for (const slug2 of capabilitySlugs) {
|
|
8435
8645
|
const capability2 = resolveCapabilityFolder(slug2, jobsRoot);
|
|
8436
8646
|
const status = await describeCapabilitySchedule(
|
|
8437
8647
|
capability2,
|
|
@@ -8442,7 +8652,7 @@ async function planGoalCapabilitySchedule(opts) {
|
|
|
8442
8652
|
statuses[slug2] = status;
|
|
8443
8653
|
if (status.state === "blocked") blockers.push(`${slug2}: ${status.reason}`);
|
|
8444
8654
|
}
|
|
8445
|
-
const due =
|
|
8655
|
+
const due = capabilitySlugs.map((slug2) => statuses[slug2]).filter((status) => status?.state === "due").sort(compareOldestLastFired)[0];
|
|
8446
8656
|
if (!due) {
|
|
8447
8657
|
const reason = blockers.length > 0 ? "no runnable capability; blocked capabilities need attention" : "no runnable capability";
|
|
8448
8658
|
const kind = blockers.length > 0 ? "blocked" : "idle";
|
|
@@ -9241,16 +9451,16 @@ function normalizeCompanyIntent(path51, raw) {
|
|
|
9241
9451
|
throw new Error(`${path51}: intent must be JSON object`);
|
|
9242
9452
|
}
|
|
9243
9453
|
const input = raw;
|
|
9244
|
-
const id =
|
|
9454
|
+
const id = stringField4(input.id);
|
|
9245
9455
|
if (!id || !isCompanyIntentId(id)) throw new Error(`${path51}: invalid intent id`);
|
|
9246
|
-
const createdAt =
|
|
9247
|
-
const updatedAt =
|
|
9248
|
-
const description =
|
|
9456
|
+
const createdAt = stringField4(input.createdAt) || nowIso();
|
|
9457
|
+
const updatedAt = stringField4(input.updatedAt) || createdAt;
|
|
9458
|
+
const description = stringField4(input.description);
|
|
9249
9459
|
return {
|
|
9250
9460
|
version: 1,
|
|
9251
9461
|
id,
|
|
9252
9462
|
status: oneOf2(input.status, ["active", "paused", "archived"], "active"),
|
|
9253
|
-
for:
|
|
9463
|
+
for: stringField4(input.for),
|
|
9254
9464
|
...description ? { description } : {},
|
|
9255
9465
|
priority: numberField(input.priority, 100),
|
|
9256
9466
|
posture: oneOf2(
|
|
@@ -9324,8 +9534,8 @@ function listCompanyPortfolio(config, cwd) {
|
|
|
9324
9534
|
goals.push({
|
|
9325
9535
|
id,
|
|
9326
9536
|
state: state.state,
|
|
9327
|
-
type:
|
|
9328
|
-
outcome:
|
|
9537
|
+
type: stringField4(state.extra.type) || void 0,
|
|
9538
|
+
outcome: stringField4(destination?.outcome) || void 0,
|
|
9329
9539
|
capabilities: stringArray4(state.extra.capabilities),
|
|
9330
9540
|
isLoop: state.extra.scheduleMode === "agentLoop" || state.extra.type === "agentLoop",
|
|
9331
9541
|
updatedAt: state.updatedAt
|
|
@@ -9340,7 +9550,7 @@ function writeCompanyGoalState(config, cwd, id, state, message) {
|
|
|
9340
9550
|
function assertIntentId(id) {
|
|
9341
9551
|
if (!isCompanyIntentId(id)) throw new Error(`invalid intent/portfolio id: ${id}`);
|
|
9342
9552
|
}
|
|
9343
|
-
function
|
|
9553
|
+
function stringField4(value) {
|
|
9344
9554
|
return typeof value === "string" ? value.trim() : "";
|
|
9345
9555
|
}
|
|
9346
9556
|
function numberField(value, fallback) {
|
|
@@ -9547,11 +9757,14 @@ function capabilityReportToEvidence(report) {
|
|
|
9547
9757
|
if (report.target.type !== "goal") return null;
|
|
9548
9758
|
const evidence = report.evidence ?? {};
|
|
9549
9759
|
const values = Object.values(evidence);
|
|
9550
|
-
const
|
|
9760
|
+
const hasFalse = values.some((value) => value === false);
|
|
9761
|
+
const hasTrue = values.some((value) => value === true);
|
|
9762
|
+
const status = hasFalse ? "fail" : values.length > 0 || report.facts ? "changed" : "noop";
|
|
9551
9763
|
return {
|
|
9552
9764
|
version: 1,
|
|
9553
9765
|
target: { type: "goal", id: report.target.id },
|
|
9554
9766
|
status,
|
|
9767
|
+
resultClass: hasFalse ? "needsFix" : hasTrue ? "succeeded" : "pending",
|
|
9555
9768
|
summary: "capability reported goal evidence",
|
|
9556
9769
|
evidence,
|
|
9557
9770
|
facts: report.facts ?? {},
|
|
@@ -9570,9 +9783,10 @@ function capabilityResultToEvidence(result, fallbackGoalId, explicitEvidence) {
|
|
|
9570
9783
|
version: 1,
|
|
9571
9784
|
target: { type: "goal", id: targetId },
|
|
9572
9785
|
status: result.status,
|
|
9786
|
+
resultClass: result.resultClass ?? resultClassFromStatus(result.status),
|
|
9573
9787
|
summary: result.summary,
|
|
9574
|
-
evidence: result.evidence,
|
|
9575
|
-
explicitEvidence
|
|
9788
|
+
...result.evidence ? { evidence: result.evidence } : {},
|
|
9789
|
+
...hasEvidenceValues || !explicitEvidence ? {} : { explicitEvidence },
|
|
9576
9790
|
facts: result.facts,
|
|
9577
9791
|
artifacts: result.artifacts,
|
|
9578
9792
|
missingEvidence: result.missingEvidence,
|
|
@@ -9604,6 +9818,7 @@ function mergeCapabilityEvidence(items) {
|
|
|
9604
9818
|
function applyCapabilityEvidenceToGoalState(state, evidence) {
|
|
9605
9819
|
const priorFacts = parseFacts3(state.extra.facts) ?? {};
|
|
9606
9820
|
const nextFacts = { ...priorFacts };
|
|
9821
|
+
const changesProgressState = evidence.sources.includes("result") || Object.entries(evidence.facts).some(([key, value]) => !CONTROL_FACT_KEYS3.has(key) && priorFacts[key] !== value) || Object.entries(evidence.evidence ?? {}).some(([key, value]) => priorFacts[key] !== value);
|
|
9607
9822
|
for (const [key, value] of Object.entries(evidence.facts)) {
|
|
9608
9823
|
if (CONTROL_FACT_KEYS3.has(key)) continue;
|
|
9609
9824
|
nextFacts[key] = value;
|
|
@@ -9614,24 +9829,42 @@ function applyCapabilityEvidenceToGoalState(state, evidence) {
|
|
|
9614
9829
|
const pending = typeof nextFacts.pendingEvidence === "string" ? nextFacts.pendingEvidence : "";
|
|
9615
9830
|
const hasEvidenceValues = Object.keys(evidence.evidence ?? {}).length > 0;
|
|
9616
9831
|
const statusEvidence = evidence.explicitEvidence || (hasEvidenceValues ? "" : pending);
|
|
9832
|
+
const progressEvidence = statusEvidence || singleEvidenceKey(evidence.evidence);
|
|
9833
|
+
const resultClass = evidence.resultClass ?? resultClassFromStatus(evidence.status);
|
|
9617
9834
|
const hasPendingEvidenceValue = pending ? Object.hasOwn(evidence.evidence ?? {}, pending) : false;
|
|
9618
|
-
const
|
|
9835
|
+
const terminalResult = resultClass === "succeeded" || resultClass === "needsFix" || resultClass === "fatal";
|
|
9619
9836
|
if (statusEvidence && !Object.hasOwn(evidence.evidence ?? {}, statusEvidence)) {
|
|
9620
|
-
if (
|
|
9621
|
-
if (
|
|
9837
|
+
if (resultClass === "succeeded") nextFacts[statusEvidence] = true;
|
|
9838
|
+
if (resultClass === "needsFix" || resultClass === "fatal") nextFacts[statusEvidence] = false;
|
|
9622
9839
|
}
|
|
9623
|
-
if (pending && (hasPendingEvidenceValue || statusEvidence === pending &&
|
|
9840
|
+
if (pending && (hasPendingEvidenceValue || statusEvidence === pending && terminalResult)) {
|
|
9624
9841
|
delete nextFacts.pendingEvidence;
|
|
9625
9842
|
}
|
|
9626
9843
|
const blockers = parseStringArray3(state.extra.blockers) ?? [];
|
|
9627
|
-
const evidenceBlockers = evidence.blockers.length > 0 ||
|
|
9844
|
+
const evidenceBlockers = evidence.blockers.length > 0 || resultClass !== "needsFix" && resultClass !== "fatal" ? evidence.blockers : [evidence.summary];
|
|
9628
9845
|
for (const blocker of evidenceBlockers) {
|
|
9629
9846
|
if (!blockers.includes(blocker)) blockers.push(blocker);
|
|
9630
9847
|
}
|
|
9848
|
+
const evidenceState = parseGoalEvidenceState(state.extra.evidenceState);
|
|
9849
|
+
const nextEvidenceState = progressEvidence && changesProgressState ? mergeGoalEvidenceProgress(evidenceState, progressEvidence, {
|
|
9850
|
+
resultClass,
|
|
9851
|
+
attempts: (evidenceState[progressEvidence]?.attempts ?? 0) + 1,
|
|
9852
|
+
reason: evidence.summary,
|
|
9853
|
+
nextAction: nextActionForResultClass(resultClass),
|
|
9854
|
+
nextRetryAt: nextRetryAtFor(state, progressEvidence, resultClass),
|
|
9855
|
+
updatedAt: nowIso()
|
|
9856
|
+
}) : evidenceState;
|
|
9631
9857
|
const nextExtra = {
|
|
9632
9858
|
...state.extra,
|
|
9633
|
-
facts: nextFacts
|
|
9859
|
+
facts: nextFacts,
|
|
9860
|
+
...changesProgressState ? {
|
|
9861
|
+
reason: evidence.summary,
|
|
9862
|
+
nextAction: progressEvidence ? nextEvidenceState[progressEvidence]?.nextAction : void 0
|
|
9863
|
+
} : {}
|
|
9634
9864
|
};
|
|
9865
|
+
if (changesProgressState || state.extra.evidenceState !== void 0) {
|
|
9866
|
+
nextExtra.evidenceState = nextEvidenceState;
|
|
9867
|
+
}
|
|
9635
9868
|
if (blockers.length > 0 || Array.isArray(state.extra.blockers)) {
|
|
9636
9869
|
nextExtra.blockers = blockers;
|
|
9637
9870
|
}
|
|
@@ -9640,6 +9873,13 @@ function applyCapabilityEvidenceToGoalState(state, evidence) {
|
|
|
9640
9873
|
extra: nextExtra
|
|
9641
9874
|
};
|
|
9642
9875
|
}
|
|
9876
|
+
function resultClassFromStatus(status) {
|
|
9877
|
+
if (status === "pass") return "succeeded";
|
|
9878
|
+
if (status === "fail") return "needsFix";
|
|
9879
|
+
if (status === "blocked") return "fatal";
|
|
9880
|
+
if (status === "noop") return "pending";
|
|
9881
|
+
return "pending";
|
|
9882
|
+
}
|
|
9643
9883
|
function evidenceMatches(report, result, allReports) {
|
|
9644
9884
|
if (report.target.id !== result.target.id) return false;
|
|
9645
9885
|
if (result.explicitEvidence && Object.hasOwn(report.evidence ?? {}, result.explicitEvidence)) return true;
|
|
@@ -9652,6 +9892,7 @@ function evidenceMatches(report, result, allReports) {
|
|
|
9652
9892
|
function mergeReportAndResult(report, result) {
|
|
9653
9893
|
return {
|
|
9654
9894
|
...result,
|
|
9895
|
+
resultClass: result.resultClass ?? report.resultClass,
|
|
9655
9896
|
evidence: mergeOptionalRecords(report.evidence, result.evidence),
|
|
9656
9897
|
facts: { ...report.facts, ...result.facts },
|
|
9657
9898
|
artifacts: uniqueArtifacts([...report.artifacts, ...result.artifacts]),
|
|
@@ -9660,6 +9901,31 @@ function mergeReportAndResult(report, result) {
|
|
|
9660
9901
|
sources: uniqueSources([...report.sources, ...result.sources])
|
|
9661
9902
|
};
|
|
9662
9903
|
}
|
|
9904
|
+
function singleEvidenceKey(evidence) {
|
|
9905
|
+
const keys = Object.keys(evidence ?? {});
|
|
9906
|
+
return keys.length === 1 ? keys[0] : "";
|
|
9907
|
+
}
|
|
9908
|
+
function nextActionForResultClass(resultClass) {
|
|
9909
|
+
if (resultClass === "succeeded") return "continue";
|
|
9910
|
+
if (resultClass === "pending") return "wait";
|
|
9911
|
+
if (resultClass === "retryable") return "retry";
|
|
9912
|
+
if (resultClass === "needsFix") return "create issue";
|
|
9913
|
+
return "block";
|
|
9914
|
+
}
|
|
9915
|
+
function nextRetryAtFor(state, evidence, resultClass) {
|
|
9916
|
+
if (resultClass !== "retryable") return void 0;
|
|
9917
|
+
const delaySeconds = retryAfterSecondsFor(state.extra.route, evidence) ?? 300;
|
|
9918
|
+
return new Date(Date.now() + delaySeconds * 1e3).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
9919
|
+
}
|
|
9920
|
+
function retryAfterSecondsFor(route, evidence) {
|
|
9921
|
+
if (!Array.isArray(route)) return void 0;
|
|
9922
|
+
const step = route.find(
|
|
9923
|
+
(item) => !!item && typeof item === "object" && !Array.isArray(item) && item.evidence === evidence
|
|
9924
|
+
);
|
|
9925
|
+
const policy = step && recordField4(step.onFailure);
|
|
9926
|
+
const retryAfter = typeof policy?.retryAfterSeconds === "number" ? policy.retryAfterSeconds : void 0;
|
|
9927
|
+
return retryAfter !== void 0 && retryAfter >= 0 ? Math.floor(retryAfter) : void 0;
|
|
9928
|
+
}
|
|
9663
9929
|
function mergeOptionalRecords(left, right) {
|
|
9664
9930
|
const merged = { ...left ?? {}, ...right ?? {} };
|
|
9665
9931
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
@@ -9705,10 +9971,15 @@ function parseStringArray3(raw) {
|
|
|
9705
9971
|
}
|
|
9706
9972
|
return out;
|
|
9707
9973
|
}
|
|
9974
|
+
function recordField4(value) {
|
|
9975
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
9976
|
+
}
|
|
9708
9977
|
var CONTROL_FACT_KEYS3;
|
|
9709
9978
|
var init_capabilityEvidence = __esm({
|
|
9710
9979
|
"src/capabilityEvidence.ts"() {
|
|
9711
9980
|
"use strict";
|
|
9981
|
+
init_evidenceState();
|
|
9982
|
+
init_state2();
|
|
9712
9983
|
CONTROL_FACT_KEYS3 = /* @__PURE__ */ new Set(["blockers", "destination", "capabilities", "route", "stage", "state"]);
|
|
9713
9984
|
}
|
|
9714
9985
|
});
|
|
@@ -9745,6 +10016,7 @@ function capabilityEvidenceOutput(evidence) {
|
|
|
9745
10016
|
kind: "capability-evidence",
|
|
9746
10017
|
sources: evidence.sources,
|
|
9747
10018
|
status: evidence.status,
|
|
10019
|
+
resultClass: evidence.resultClass,
|
|
9748
10020
|
summary: evidence.summary,
|
|
9749
10021
|
evidence: evidence.evidence ?? {},
|
|
9750
10022
|
facts: evidence.facts,
|
|
@@ -9756,7 +10028,7 @@ function capabilityEvidenceOutput(evidence) {
|
|
|
9756
10028
|
function goalReportBody(goalId, state, snapshot, latestEvent, evidenceItems) {
|
|
9757
10029
|
const outputs = evidenceItems.map(capabilityEvidenceOutput);
|
|
9758
10030
|
const latestOutput = outputs.at(-1);
|
|
9759
|
-
const facts =
|
|
10031
|
+
const facts = recordField5(snapshot, "facts") ?? recordField5(state.extra, "facts") ?? {};
|
|
9760
10032
|
const blockers = uniqueStrings2([
|
|
9761
10033
|
...stringArrayField(snapshot, "blockers"),
|
|
9762
10034
|
...stringArrayField(latestEvent, "blockers"),
|
|
@@ -9775,12 +10047,12 @@ function goalReportBody(goalId, state, snapshot, latestEvent, evidenceItems) {
|
|
|
9775
10047
|
"",
|
|
9776
10048
|
"## Status",
|
|
9777
10049
|
`- State: ${state.state}`,
|
|
9778
|
-
`- Stage: ${
|
|
10050
|
+
`- Stage: ${stringField5(snapshot, "stage") ?? stringField5(state.extra, "stage") ?? "unknown"}`,
|
|
9779
10051
|
`- Next step: ${nextStepFromEvent(state, snapshot, latestOutput, latestEvent)}`,
|
|
9780
10052
|
`- Updated: ${state.updatedAt ?? state.createdAt ?? state.startedAt ?? "unknown"}`,
|
|
9781
10053
|
"",
|
|
9782
10054
|
"## Decision",
|
|
9783
|
-
`- Event: ${
|
|
10055
|
+
`- Event: ${stringField5(latestEvent, "event") ?? "unknown"}`,
|
|
9784
10056
|
`- Reason: ${decisionReason(state, latestEvent, latestOutput, missingEvidence, blockers)}`,
|
|
9785
10057
|
`- Required evidence: ${listOrNone(stringArrayField(snapshot, "requiredEvidence"))}`,
|
|
9786
10058
|
`- Satisfied evidence: ${listOrNone(stringArrayField(snapshot, "satisfiedEvidence"))}`,
|
|
@@ -9808,9 +10080,9 @@ function capabilityEvidenceMarkdown(outputs) {
|
|
|
9808
10080
|
function decisionReason(state, latestEvent, latestOutput, missingEvidence, blockers) {
|
|
9809
10081
|
if (state.state === "done") return "destination evidence satisfied";
|
|
9810
10082
|
if (blockers.length > 0) return blockers[0] ?? "blocked";
|
|
9811
|
-
const eventReason =
|
|
10083
|
+
const eventReason = stringField5(latestEvent, "reason") ?? stringField5(recordField5(latestEvent, "decision"), "reason");
|
|
9812
10084
|
if (eventReason) return eventReason;
|
|
9813
|
-
const summary =
|
|
10085
|
+
const summary = stringField5(latestOutput, "summary");
|
|
9814
10086
|
if (summary) return summary;
|
|
9815
10087
|
if (missingEvidence.length > 0) return `waiting for ${missingEvidence[0]}`;
|
|
9816
10088
|
return "waiting for more evidence";
|
|
@@ -9818,33 +10090,33 @@ function decisionReason(state, latestEvent, latestOutput, missingEvidence, block
|
|
|
9818
10090
|
function evidenceOutputMarkdown(index, output) {
|
|
9819
10091
|
return [
|
|
9820
10092
|
`### Output ${index}`,
|
|
9821
|
-
`- Status: ${
|
|
9822
|
-
`- Summary: ${
|
|
10093
|
+
`- Status: ${stringField5(output, "status") ?? "unknown"}`,
|
|
10094
|
+
`- Summary: ${stringField5(output, "summary") ?? "no summary"}`,
|
|
9823
10095
|
`- Sources: ${listOrNone(stringArrayField(output, "sources"))}`,
|
|
9824
|
-
`- Evidence values: ${inlineJson(
|
|
10096
|
+
`- Evidence values: ${inlineJson(recordField5(output, "evidence") ?? {})}`,
|
|
9825
10097
|
`- Missing evidence: ${listOrNone(stringArrayField(output, "missingEvidence"))}`,
|
|
9826
10098
|
`- Blockers: ${listOrNone(stringArrayField(output, "blockers"))}`,
|
|
9827
10099
|
""
|
|
9828
10100
|
];
|
|
9829
10101
|
}
|
|
9830
10102
|
function dispatchContextMarkdown(latestEvent) {
|
|
9831
|
-
const context =
|
|
10103
|
+
const context = recordField5(latestEvent, "dispatchContext");
|
|
9832
10104
|
if (!context) return ["- none"];
|
|
9833
|
-
const githubActor =
|
|
9834
|
-
const githubActorRole =
|
|
9835
|
-
const target = dispatchTargetLabel(
|
|
10105
|
+
const githubActor = stringField5(context, "githubActor");
|
|
10106
|
+
const githubActorRole = stringField5(context, "githubActorRole");
|
|
10107
|
+
const target = dispatchTargetLabel(recordField5(context, "target"));
|
|
9836
10108
|
return [
|
|
9837
|
-
`- Triggered by: ${
|
|
9838
|
-
`- Mode: ${
|
|
10109
|
+
`- Triggered by: ${stringField5(context, "triggeredBy") ?? "unknown"}`,
|
|
10110
|
+
`- Mode: ${stringField5(context, "dispatchMode") ?? "unknown"}`,
|
|
9839
10111
|
`- GitHub actor: ${githubActor ? `${githubActor}${githubActorRole ? ` (${githubActorRole})` : ""}` : "none"}`,
|
|
9840
|
-
`- Decided by: ${
|
|
9841
|
-
`- Dispatched by: ${
|
|
10112
|
+
`- Decided by: ${stringField5(context, "decidedBy") ?? "unknown"}`,
|
|
10113
|
+
`- Dispatched by: ${stringField5(context, "dispatchedBy") ?? "unknown"}`,
|
|
9842
10114
|
`- Target: ${target ?? "none"}`
|
|
9843
10115
|
];
|
|
9844
10116
|
}
|
|
9845
10117
|
function dispatchTargetLabel(target) {
|
|
9846
|
-
const type =
|
|
9847
|
-
const id =
|
|
10118
|
+
const type = stringField5(target, "type");
|
|
10119
|
+
const id = stringField5(target, "id");
|
|
9848
10120
|
if (type && id) return `${type} ${id}`;
|
|
9849
10121
|
return id ?? type;
|
|
9850
10122
|
}
|
|
@@ -9867,11 +10139,11 @@ function listOrNone(values) {
|
|
|
9867
10139
|
function uniqueStrings2(values) {
|
|
9868
10140
|
return [...new Set(values)].sort();
|
|
9869
10141
|
}
|
|
9870
|
-
function
|
|
10142
|
+
function stringField5(record2, key) {
|
|
9871
10143
|
const value = record2?.[key];
|
|
9872
10144
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
9873
10145
|
}
|
|
9874
|
-
function
|
|
10146
|
+
function recordField5(record2, key) {
|
|
9875
10147
|
const value = record2?.[key];
|
|
9876
10148
|
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : void 0;
|
|
9877
10149
|
}
|
|
@@ -9904,7 +10176,7 @@ ${artifact.path ?? ""}`;
|
|
|
9904
10176
|
}
|
|
9905
10177
|
function nextStepFromEvent(state, goalAfter, capabilityOutput, latestEvent) {
|
|
9906
10178
|
if (state.state === "done") return "done";
|
|
9907
|
-
const decisionKind =
|
|
10179
|
+
const decisionKind = stringField5(recordField5(latestEvent, "decision"), "kind") ?? stringField5(latestEvent, "status");
|
|
9908
10180
|
if (decisionKind === "done") return "done";
|
|
9909
10181
|
if (decisionKind === "dispatch") return "dispatch";
|
|
9910
10182
|
if (decisionKind === "blocked" || decisionKind === "reject-evidence") return "block";
|
|
@@ -9954,6 +10226,64 @@ var init_report = __esm({
|
|
|
9954
10226
|
});
|
|
9955
10227
|
|
|
9956
10228
|
// src/scripts/applyCapabilityReports.ts
|
|
10229
|
+
function ensureNeedsFixIssue(ctx, goalId, state, evidence, evidenceKey) {
|
|
10230
|
+
if (evidence.resultClass !== "needsFix" || !evidenceKey) return state;
|
|
10231
|
+
const evidenceState = parseGoalEvidenceState(state.extra.evidenceState);
|
|
10232
|
+
const progress = evidenceState[evidenceKey];
|
|
10233
|
+
if (progress?.issue) return state;
|
|
10234
|
+
const issue = findExistingNeedsFixIssue(goalId, evidenceKey, ctx.cwd) ?? createNeedsFixIssue(goalId, evidenceKey, evidence, ctx.cwd);
|
|
10235
|
+
const nextEvidenceState = mergeGoalEvidenceProgress(evidenceState, evidenceKey, {
|
|
10236
|
+
resultClass: "needsFix",
|
|
10237
|
+
attempts: progress?.attempts ?? 1,
|
|
10238
|
+
reason: evidence.summary,
|
|
10239
|
+
nextAction: `fix issue #${issue}`,
|
|
10240
|
+
issue,
|
|
10241
|
+
updatedAt: nowIso()
|
|
10242
|
+
});
|
|
10243
|
+
return {
|
|
10244
|
+
...state,
|
|
10245
|
+
extra: {
|
|
10246
|
+
...state.extra,
|
|
10247
|
+
evidenceState: nextEvidenceState,
|
|
10248
|
+
reason: evidence.summary,
|
|
10249
|
+
nextAction: `fix issue #${issue}`
|
|
10250
|
+
}
|
|
10251
|
+
};
|
|
10252
|
+
}
|
|
10253
|
+
function evidenceKeyFromOutput(evidence, beforeSnapshot) {
|
|
10254
|
+
if (evidence.explicitEvidence) return evidence.explicitEvidence;
|
|
10255
|
+
const keys = Object.keys(evidence.evidence ?? {});
|
|
10256
|
+
if (keys.length === 1) return keys[0];
|
|
10257
|
+
const pending = beforeSnapshot?.pendingEvidence;
|
|
10258
|
+
return typeof pending === "string" ? pending : "";
|
|
10259
|
+
}
|
|
10260
|
+
function needsFixIssueMarker(goalId, evidence) {
|
|
10261
|
+
return `<!-- kody-managed-goal-needs-fix: ${goalId}:${evidence} -->`;
|
|
10262
|
+
}
|
|
10263
|
+
function findExistingNeedsFixIssue(goalId, evidence, cwd) {
|
|
10264
|
+
const marker = needsFixIssueMarker(goalId, evidence);
|
|
10265
|
+
const raw = gh(["issue", "list", "--state", "all", "--limit", "100", "--json", "number,body"], { cwd });
|
|
10266
|
+
const issues = JSON.parse(raw);
|
|
10267
|
+
const match = issues.find((issue) => typeof issue.number === "number" && issue.body?.includes(marker));
|
|
10268
|
+
return match?.number ?? null;
|
|
10269
|
+
}
|
|
10270
|
+
function createNeedsFixIssue(goalId, evidence, result, cwd) {
|
|
10271
|
+
const title = `Goal ${goalId}: fix ${evidence}`.slice(0, 120);
|
|
10272
|
+
const body = [
|
|
10273
|
+
`Managed goal: \`${goalId}\``,
|
|
10274
|
+
`Evidence: \`${evidence}\``,
|
|
10275
|
+
"",
|
|
10276
|
+
`Reason: ${result.summary}`,
|
|
10277
|
+
"",
|
|
10278
|
+
result.blockers.length > 0 ? `Blockers: ${result.blockers.join(", ")}` : "Blockers: none",
|
|
10279
|
+
"",
|
|
10280
|
+
needsFixIssueMarker(goalId, evidence)
|
|
10281
|
+
].join("\n");
|
|
10282
|
+
const out = gh(["issue", "create", "--title", title, "--body-file", "-"], { input: body, cwd });
|
|
10283
|
+
const match = out.match(/\/issues\/(\d+)(?:[/?#]|$)/);
|
|
10284
|
+
if (!match) throw new Error(`gh issue create returned unexpected output: ${out}`);
|
|
10285
|
+
return Number(match[1]);
|
|
10286
|
+
}
|
|
9957
10287
|
function flushLogs(ctx) {
|
|
9958
10288
|
try {
|
|
9959
10289
|
flushGoalRunLogEvents(ctx.config, ctx.cwd, ctx.data);
|
|
@@ -10046,15 +10376,13 @@ function completeSatisfiedManagedGoal(state) {
|
|
|
10046
10376
|
if (decision.kind !== "done") return state;
|
|
10047
10377
|
return writeManagedGoalToState({ ...state, state: "done" }, managed);
|
|
10048
10378
|
}
|
|
10049
|
-
function shouldResumeManagedGoal(state) {
|
|
10379
|
+
function shouldResumeManagedGoal(goalId, state) {
|
|
10050
10380
|
if (state.state !== "active") return false;
|
|
10051
10381
|
const managed = managedGoalFromState(state);
|
|
10052
10382
|
if (!managed) return false;
|
|
10053
10383
|
if (managed.blockers.length > 0) return false;
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
const step = managed.route.find((candidate) => candidate.evidence === missing);
|
|
10057
|
-
return Boolean(step && managed.capabilities.includes(step.capability));
|
|
10384
|
+
if (managed.facts.goalId === void 0) managed.facts.goalId = goalId;
|
|
10385
|
+
return planManagedGoalTick(managed).kind === "dispatch";
|
|
10058
10386
|
}
|
|
10059
10387
|
function snapshotFromState2(goalId, state) {
|
|
10060
10388
|
const managed = managedGoalFromState(state);
|
|
@@ -10111,11 +10439,13 @@ var init_applyCapabilityReports = __esm({
|
|
|
10111
10439
|
init_capabilityEvidence();
|
|
10112
10440
|
init_capabilityReport();
|
|
10113
10441
|
init_capabilityResult();
|
|
10442
|
+
init_evidenceState();
|
|
10114
10443
|
init_manager();
|
|
10115
10444
|
init_report();
|
|
10116
10445
|
init_runLog();
|
|
10117
10446
|
init_state2();
|
|
10118
10447
|
init_stateStore();
|
|
10448
|
+
init_issue();
|
|
10119
10449
|
applyCapabilityReports = async (ctx, _profile, agentResult) => {
|
|
10120
10450
|
const reports = collectReports(ctx.data.capabilityReports, agentResult);
|
|
10121
10451
|
const results = collectResults(ctx.data.capabilityResults ?? ctx.data.dutyResults, agentResult);
|
|
@@ -10153,6 +10483,7 @@ var init_applyCapabilityReports = __esm({
|
|
|
10153
10483
|
for (const evidence of goalEvidence) {
|
|
10154
10484
|
const beforeSnapshot = snapshotFromState2(goalId, next);
|
|
10155
10485
|
next = applyCapabilityEvidenceToGoalState(next, evidence);
|
|
10486
|
+
next = ensureNeedsFixIssue(ctx, goalId, next, evidence, evidenceKeyFromOutput(evidence, beforeSnapshot));
|
|
10156
10487
|
const afterSnapshot = snapshotFromState2(goalId, next);
|
|
10157
10488
|
const change = goalRunLogChange(beforeSnapshot, afterSnapshot);
|
|
10158
10489
|
const output = capabilityEvidenceOutput(evidence);
|
|
@@ -10203,7 +10534,7 @@ var init_applyCapabilityReports = __esm({
|
|
|
10203
10534
|
putGoalState(ctx.config, goalId, nextForOutput, describeMessage(goalId, goalEvidence), ctx.cwd);
|
|
10204
10535
|
}
|
|
10205
10536
|
refreshReportOrFail(ctx, goalId, nextForOutput, goalEvidence);
|
|
10206
|
-
if (changed && ctx.output.exitCode === 0 && !ctx.output.nextDispatch && shouldResumeManagedGoal(nextForOutput)) {
|
|
10537
|
+
if (changed && ctx.output.exitCode === 0 && !ctx.output.nextDispatch && shouldResumeManagedGoal(goalId, nextForOutput)) {
|
|
10207
10538
|
ctx.output.nextDispatch = {
|
|
10208
10539
|
action: "goal-manager",
|
|
10209
10540
|
executable: "goal-manager",
|
|
@@ -21650,6 +21981,15 @@ async function runCi(argv) {
|
|
|
21650
21981
|
}
|
|
21651
21982
|
const args = parseCiArgs(argv);
|
|
21652
21983
|
const cwd = args.cwd ? path46.resolve(args.cwd) : process.cwd();
|
|
21984
|
+
try {
|
|
21985
|
+
const n = unpackAllSecrets();
|
|
21986
|
+
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
21987
|
+
`);
|
|
21988
|
+
await resolveAuthToken();
|
|
21989
|
+
} catch (err) {
|
|
21990
|
+
process.stderr.write(`[kody] auth setup warning: ${err instanceof Error ? err.message : String(err)}
|
|
21991
|
+
`);
|
|
21992
|
+
}
|
|
21653
21993
|
let earlyConfig;
|
|
21654
21994
|
let earlyConfigError;
|
|
21655
21995
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.323",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|