hippo-memory 1.40.0 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/card.d.ts +3 -1
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +4 -1
- package/dist/card.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +93 -18
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/src/card.js +4 -1
- package/dist/src/card.js.map +1 -1
- package/dist/src/cli.js +93 -18
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/store.js +122 -22
- package/dist/src/store.js.map +1 -1
- package/dist/src/version.js +2 -15
- package/dist/src/version.js.map +1 -1
- package/dist/store.d.ts +14 -8
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +122 -22
- package/dist/store.js.map +1 -1
- package/dist/version.d.ts +2 -15
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -15
- package/dist/version.js.map +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -622,10 +622,12 @@ hippo watch "npm run build"
|
|
|
622
622
|
| `hippo card create --title "..."` | Create a work-queue card (`--repo`, `--contract`, `--budget`, repeatable `--depends-on <id>`) |
|
|
623
623
|
| `hippo card show <id>` | Show a card, its deps, runs, comments and latest handoff |
|
|
624
624
|
| `hippo card list [--status <status>]` | List cards, newest-updated first |
|
|
625
|
-
| `hippo card claim <id> --runtime <name>` | Claim a ready or blocked card |
|
|
626
|
-
| `hippo card
|
|
627
|
-
| `hippo card
|
|
628
|
-
| `hippo card
|
|
625
|
+
| `hippo card claim <id> --runtime <name>` | Claim a ready or blocked card; prints its run id and the time its 4-hour lease expires |
|
|
626
|
+
| `hippo card heartbeat <id> --run <n>` | Extend a claimed card's lease |
|
|
627
|
+
| `hippo card block <id> --reason "<why>" [--run <n>]` | Block a running card; the reason is recorded as a comment |
|
|
628
|
+
| `hippo card review <id> [--run <n>]` | Move a running card to review |
|
|
629
|
+
| `hippo card complete <id> --outcome <success\|failure\|partial> [--run <n>]` | Complete a card in review: `success` marks it done and promotes children whose parents are all done; `failure` or `partial` shelves it |
|
|
630
|
+
| `hippo card reclaim` | Sweep every card whose lease has passed and return it to ready |
|
|
629
631
|
| `hippo card comment <id> --body "..."` | Add a comment to a card |
|
|
630
632
|
| `hippo wm push --scope <s> --content "..."` | Push to working memory |
|
|
631
633
|
| `hippo wm read --scope <s>` | Read working memory entries |
|
|
@@ -635,6 +637,8 @@ hippo watch "npm run build"
|
|
|
635
637
|
| `hippo dashboard --port <n>` | Use custom port |
|
|
636
638
|
| `hippo mcp` | Start MCP server (stdio transport) |
|
|
637
639
|
|
|
640
|
+
On `heartbeat`, `block`, `review` and `complete`, a given `--run` is checked against the card's live run and the command is refused, unchanged, if the two do not match.
|
|
641
|
+
|
|
638
642
|
---
|
|
639
643
|
|
|
640
644
|
## Framework Integrations
|
package/dist/card.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export type CardStatus = 'backlog' | 'ready' | 'running' | 'blocked' | 'review' | 'done' | 'shelved';
|
|
3
3
|
/** Narrows a raw string, such as a CLI flag value, to a CardStatus. */
|
|
4
4
|
export declare function isCardStatus(v: string): v is CardStatus;
|
|
5
|
-
/** A card row; leaseUntil and heartbeatAt are
|
|
5
|
+
/** A card row; leaseUntil and heartbeatAt are null unless the card is running, and a card claimed under 1.40.0 runs with both null until a heartbeat sets them. */
|
|
6
6
|
export interface Card {
|
|
7
7
|
id: string;
|
|
8
8
|
title: string;
|
|
@@ -42,4 +42,6 @@ export type CardTransitions = {
|
|
|
42
42
|
};
|
|
43
43
|
/** transitionCard checks every status write against this map. */
|
|
44
44
|
export declare const CARD_TRANSITIONS: CardTransitions;
|
|
45
|
+
/** How long a claim or a heartbeat keeps a running card's lease before reclaimExpiredCards may return it to ready. */
|
|
46
|
+
export declare const CARD_LEASE_MS: number;
|
|
45
47
|
//# sourceMappingURL=card.d.ts.map
|
package/dist/card.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AACA,gGAAgG;AAChG,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAIrG,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,UAAU,CAEvD;AAED,
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AACA,gGAAgG;AAChG,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAIrG,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,UAAU,CAEvD;AAED,mKAAmK;AACnK,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,yDAAyD;AACzD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,mDAAmD;AACnD,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,UAAU,GAAG,SAAS,UAAU,EAAE;CAAE,CAAC;AAEpF,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,eAQ9B,CAAC;AAGF,sHAAsH;AACtH,eAAO,MAAM,aAAa,QAAqB,CAAC"}
|
package/dist/card.js
CHANGED
|
@@ -7,10 +7,13 @@ export function isCardStatus(v) {
|
|
|
7
7
|
export const CARD_TRANSITIONS = {
|
|
8
8
|
backlog: ['ready'],
|
|
9
9
|
ready: ['running'],
|
|
10
|
-
running: ['blocked', 'review'],
|
|
10
|
+
running: ['blocked', 'review', 'ready'],
|
|
11
11
|
blocked: ['running'],
|
|
12
12
|
review: ['done', 'shelved'],
|
|
13
13
|
done: [],
|
|
14
14
|
shelved: [],
|
|
15
15
|
};
|
|
16
|
+
// SHORTCUT: one fixed lease for every claim; add a per-claim lease when the W3 dispatcher heartbeats on a timer.
|
|
17
|
+
/** How long a claim or a heartbeat keeps a running card's lease before reclaimExpiredCards may return it to ready. */
|
|
18
|
+
export const CARD_LEASE_MS = 4 * 60 * 60 * 1000;
|
|
16
19
|
//# sourceMappingURL=card.js.map
|
package/dist/card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card.js","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AAIA,MAAM,aAAa,GAA0B,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAErH,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,CAAC;AA0CD,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,OAAO,EAAE,CAAC,OAAO,CAAC;IAClB,KAAK,EAAE,CAAC,SAAS,CAAC;IAClB,OAAO,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AAIA,MAAM,aAAa,GAA0B,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAErH,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,CAAC;AA0CD,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,OAAO,EAAE,CAAC,OAAO,CAAC;IAClB,KAAK,EAAE,CAAC,SAAS,CAAC;IAClB,OAAO,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC;IACvC,OAAO,EAAE,CAAC,SAAS,CAAC;IACpB,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF,iHAAiH;AACjH,sHAAsH;AACtH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* hippo snapshot <save|show|clear>
|
|
14
14
|
* hippo session <log|show|latest|resume|complete>
|
|
15
15
|
* hippo handoff <create|latest|show>
|
|
16
|
-
* hippo card <create|show|list|claim|block|review|complete|comment>
|
|
16
|
+
* hippo card <create|show|list|claim|heartbeat|block|review|complete|reclaim|comment>
|
|
17
17
|
* hippo current <show>
|
|
18
18
|
* hippo forget <id> [--archive --reason "<why>"]
|
|
19
19
|
* hippo reject <id>|--value "<text>" --reason "<why>"
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AA2BH,OAAO,EAWL,WAAW,EAEZ,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AA2BH,OAAO,EAWL,WAAW,EAEZ,MAAM,aAAa,CAAC;AA6HrB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA4ChC,kFAAkF;AAClF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAsJD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;CAAE,CAwCjI;AAqxED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,MAAqB,GAAG,MAAM,CAyF3F;AAyGD;;;GAGG;AACH,oHAAoH;AACpH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAuD/D;AAigHD,oHAAoH;AACpH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,EACtF,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAkB,GAC1B,IAAI,CA8BN"}
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* hippo snapshot <save|show|clear>
|
|
14
14
|
* hippo session <log|show|latest|resume|complete>
|
|
15
15
|
* hippo handoff <create|latest|show>
|
|
16
|
-
* hippo card <create|show|list|claim|block|review|complete|comment>
|
|
16
|
+
* hippo card <create|show|list|claim|heartbeat|block|review|complete|reclaim|comment>
|
|
17
17
|
* hippo current <show>
|
|
18
18
|
* hippo forget <id> [--archive --reason "<why>"]
|
|
19
19
|
* hippo reject <id>|--value "<text>" --reason "<why>"
|
|
@@ -38,7 +38,7 @@ import { execFileSync, execSync, spawn } from 'child_process';
|
|
|
38
38
|
import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, isCodexWrapperInstalled, repairCodexWrapperIfInstalled, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
|
|
39
39
|
import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, confidenceFacets, confidenceLabel, computeSchemaFit, Layer, } from './memory.js';
|
|
40
40
|
import { detectSecret } from './secret-detect.js';
|
|
41
|
-
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadRecallSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, closeTaskSnapshotsForSession, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, stampHandoffOutcome, writeSessionEndHandoff, createCard, loadCard, listCards, loadCardDeps, loadCardRuns, loadCardComments, claimCard, blockCard, reviewCard, completeCard, addCardComment, loadLatestHandoffForCard, } from './store.js';
|
|
41
|
+
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadRecallSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, closeTaskSnapshotsForSession, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, stampHandoffOutcome, writeSessionEndHandoff, createCard, loadCard, listCards, loadCardDeps, loadCardRuns, loadCardComments, claimCard, heartbeatCard, blockCard, reviewCard, completeCard, reclaimExpiredCards, addCardComment, loadLatestHandoffForCard, } from './store.js';
|
|
42
42
|
import { rejectValue, unrejectValue, listRejectionsForTenant } from './reject-flow.js';
|
|
43
43
|
import { RejectedValueError } from './rejection.js';
|
|
44
44
|
import { isHandoffOutcome, formatHandoffEvidenceLine } from './handoff.js';
|
|
@@ -4034,6 +4034,10 @@ function printCard(hippoRoot, tenantId, card) {
|
|
|
4034
4034
|
console.log(`- Status: ${card.status}`);
|
|
4035
4035
|
if (card.assigneeRuntime)
|
|
4036
4036
|
console.log(`- Assignee: ${card.assigneeRuntime}`);
|
|
4037
|
+
if (card.leaseUntil)
|
|
4038
|
+
console.log(`- Lease until: ${card.leaseUntil}`);
|
|
4039
|
+
if (card.heartbeatAt)
|
|
4040
|
+
console.log(`- Heartbeat: ${card.heartbeatAt}`);
|
|
4037
4041
|
if (card.repo)
|
|
4038
4042
|
console.log(`- Repo: ${card.repo}`);
|
|
4039
4043
|
if (card.contract)
|
|
@@ -4050,7 +4054,7 @@ function printCard(hippoRoot, tenantId, card) {
|
|
|
4050
4054
|
if (runs.length > 0) {
|
|
4051
4055
|
console.log('\n### Runs');
|
|
4052
4056
|
for (const run of runs) {
|
|
4053
|
-
console.log(`- ${run.runtime} started ${run.started}${run.ended ? ` ended ${run.ended} (${run.outcome})` : ' (open)'}`);
|
|
4057
|
+
console.log(`- run ${run.id}: ${run.runtime} started ${run.started}${run.ended ? ` ended ${run.ended} (${run.outcome})` : ' (open)'}`);
|
|
4054
4058
|
}
|
|
4055
4059
|
}
|
|
4056
4060
|
const comments = loadCardComments(hippoRoot, tenantId, card.id);
|
|
@@ -4080,14 +4084,34 @@ function cardStringFlag(flags, key) {
|
|
|
4080
4084
|
}
|
|
4081
4085
|
return v.trim();
|
|
4082
4086
|
}
|
|
4087
|
+
// A too-large --run would silently round to a different id (mirrors parsePositiveIncidentId).
|
|
4088
|
+
function cardRunFlag(flags) {
|
|
4089
|
+
const raw = cardStringFlag(flags, 'run');
|
|
4090
|
+
if (raw === undefined)
|
|
4091
|
+
return undefined;
|
|
4092
|
+
const n = Number(raw);
|
|
4093
|
+
if (!/^\d+$/.test(raw) || !Number.isSafeInteger(n) || n <= 0) {
|
|
4094
|
+
console.error(`Invalid --run: "${raw}" (expected a positive integer).`);
|
|
4095
|
+
process.exit(1);
|
|
4096
|
+
}
|
|
4097
|
+
return n;
|
|
4098
|
+
}
|
|
4099
|
+
// Reads after the store already refused, so this only explains the refusal, never changes it.
|
|
4100
|
+
function cardRefusal(hippoRoot, tenantId, id) {
|
|
4101
|
+
const card = loadCard(hippoRoot, tenantId, id);
|
|
4102
|
+
const liveRun = loadCardRuns(hippoRoot, tenantId, id).find((r) => !r.ended);
|
|
4103
|
+
return `status ${card?.status ?? 'unknown'}, live run ${liveRun?.id ?? 'none'}`;
|
|
4104
|
+
}
|
|
4083
4105
|
const CARD_SUBCOMMAND_FLAGS = {
|
|
4084
4106
|
create: ['title', 'repo', 'contract', 'budget', 'depends-on'],
|
|
4085
4107
|
show: ['json'],
|
|
4086
4108
|
list: ['status', 'json'],
|
|
4087
4109
|
claim: ['runtime', 'session'],
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4110
|
+
heartbeat: ['run'],
|
|
4111
|
+
block: ['reason', 'run'],
|
|
4112
|
+
review: ['run'],
|
|
4113
|
+
complete: ['outcome', 'run'],
|
|
4114
|
+
reclaim: new Array(),
|
|
4091
4115
|
comment: ['body', 'author'],
|
|
4092
4116
|
};
|
|
4093
4117
|
function cmdCard(hippoRoot, args, flags) {
|
|
@@ -4205,7 +4229,29 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4205
4229
|
console.error(`Could not claim card ${id} (not ready/blocked, or already claimed).`);
|
|
4206
4230
|
process.exit(1);
|
|
4207
4231
|
}
|
|
4208
|
-
console.log(`Claimed card ${card.id} for ${runtime}`);
|
|
4232
|
+
console.log(`Claimed card ${card.id} for ${runtime} (run ${card.runId}, lease until ${card.leaseUntil})`);
|
|
4233
|
+
return;
|
|
4234
|
+
}
|
|
4235
|
+
if (subcommand === 'heartbeat') {
|
|
4236
|
+
const id = args[1];
|
|
4237
|
+
const runId = cardRunFlag(flags);
|
|
4238
|
+
if (!id || runId === undefined) {
|
|
4239
|
+
console.error('Usage: hippo card heartbeat <id> --run <n>');
|
|
4240
|
+
process.exit(1);
|
|
4241
|
+
}
|
|
4242
|
+
let card;
|
|
4243
|
+
try {
|
|
4244
|
+
card = heartbeatCard(hippoRoot, tenantId, id, runId);
|
|
4245
|
+
}
|
|
4246
|
+
catch (error) {
|
|
4247
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
4248
|
+
process.exit(1);
|
|
4249
|
+
}
|
|
4250
|
+
if (!card) {
|
|
4251
|
+
console.error(`Could not heartbeat card ${id} (${cardRefusal(hippoRoot, tenantId, id)}).`);
|
|
4252
|
+
process.exit(1);
|
|
4253
|
+
}
|
|
4254
|
+
console.log(`Heartbeat card ${card.id}: lease until ${card.leaseUntil}`);
|
|
4209
4255
|
return;
|
|
4210
4256
|
}
|
|
4211
4257
|
if (subcommand === 'block') {
|
|
@@ -4215,16 +4261,18 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4215
4261
|
console.error(CARD_BLOCK_REASON_REQUIRED);
|
|
4216
4262
|
process.exit(1);
|
|
4217
4263
|
}
|
|
4264
|
+
const runId = cardRunFlag(flags);
|
|
4218
4265
|
let card;
|
|
4219
4266
|
try {
|
|
4220
|
-
card = blockCard(hippoRoot, tenantId, id, reason);
|
|
4267
|
+
card = blockCard(hippoRoot, tenantId, id, reason, runId);
|
|
4221
4268
|
}
|
|
4222
4269
|
catch (error) {
|
|
4223
4270
|
console.error(error instanceof Error ? error.message : String(error));
|
|
4224
4271
|
process.exit(1);
|
|
4225
4272
|
}
|
|
4226
4273
|
if (!card) {
|
|
4227
|
-
|
|
4274
|
+
const why = runId === undefined ? 'not running' : cardRefusal(hippoRoot, tenantId, id);
|
|
4275
|
+
console.error(`Could not block card ${id} (${why}).`);
|
|
4228
4276
|
process.exit(1);
|
|
4229
4277
|
}
|
|
4230
4278
|
console.log(`Blocked card ${card.id}`);
|
|
@@ -4233,19 +4281,21 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4233
4281
|
if (subcommand === 'review') {
|
|
4234
4282
|
const id = args[1];
|
|
4235
4283
|
if (!id) {
|
|
4236
|
-
console.error('Usage: hippo card review <id>');
|
|
4284
|
+
console.error('Usage: hippo card review <id> [--run <n>]');
|
|
4237
4285
|
process.exit(1);
|
|
4238
4286
|
}
|
|
4287
|
+
const runId = cardRunFlag(flags);
|
|
4239
4288
|
let card;
|
|
4240
4289
|
try {
|
|
4241
|
-
card = reviewCard(hippoRoot, tenantId, id);
|
|
4290
|
+
card = reviewCard(hippoRoot, tenantId, id, runId);
|
|
4242
4291
|
}
|
|
4243
4292
|
catch (error) {
|
|
4244
4293
|
console.error(error instanceof Error ? error.message : String(error));
|
|
4245
4294
|
process.exit(1);
|
|
4246
4295
|
}
|
|
4247
4296
|
if (!card) {
|
|
4248
|
-
|
|
4297
|
+
const why = runId === undefined ? 'not running' : cardRefusal(hippoRoot, tenantId, id);
|
|
4298
|
+
console.error(`Could not move card ${id} to review (${why}).`);
|
|
4249
4299
|
process.exit(1);
|
|
4250
4300
|
}
|
|
4251
4301
|
console.log(`Card ${card.id} moved to review`);
|
|
@@ -4255,19 +4305,21 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4255
4305
|
const id = args[1];
|
|
4256
4306
|
const outcomeRaw = flags['outcome'];
|
|
4257
4307
|
if (!id || !isHandoffOutcome(outcomeRaw)) {
|
|
4258
|
-
console.error('Usage: hippo card complete <id> --outcome <success|failure|partial>');
|
|
4308
|
+
console.error('Usage: hippo card complete <id> --outcome <success|failure|partial> [--run <n>]');
|
|
4259
4309
|
process.exit(1);
|
|
4260
4310
|
}
|
|
4311
|
+
const runId = cardRunFlag(flags);
|
|
4261
4312
|
let result;
|
|
4262
4313
|
try {
|
|
4263
|
-
result = completeCard(hippoRoot, tenantId, id, outcomeRaw);
|
|
4314
|
+
result = completeCard(hippoRoot, tenantId, id, outcomeRaw, runId);
|
|
4264
4315
|
}
|
|
4265
4316
|
catch (error) {
|
|
4266
4317
|
console.error(error instanceof Error ? error.message : String(error));
|
|
4267
4318
|
process.exit(1);
|
|
4268
4319
|
}
|
|
4269
4320
|
if (!result) {
|
|
4270
|
-
|
|
4321
|
+
const why = runId === undefined ? 'not in review' : cardRefusal(hippoRoot, tenantId, id);
|
|
4322
|
+
console.error(`Could not complete card ${id} (${why}).`);
|
|
4271
4323
|
process.exit(1);
|
|
4272
4324
|
}
|
|
4273
4325
|
console.log(`Completed card ${result.card.id} (status: ${result.card.status})`);
|
|
@@ -4276,13 +4328,28 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4276
4328
|
}
|
|
4277
4329
|
return;
|
|
4278
4330
|
}
|
|
4331
|
+
if (subcommand === 'reclaim') {
|
|
4332
|
+
if (args.length > 1) {
|
|
4333
|
+
console.error('Usage: hippo card reclaim (sweeps every expired lease; use hippo card block <id> for one card)');
|
|
4334
|
+
process.exit(1);
|
|
4335
|
+
}
|
|
4336
|
+
const ids = reclaimExpiredCards(hippoRoot, tenantId);
|
|
4337
|
+
if (ids.length === 0) {
|
|
4338
|
+
console.log('No expired leases.');
|
|
4339
|
+
return;
|
|
4340
|
+
}
|
|
4341
|
+
for (const id of ids) {
|
|
4342
|
+
console.log(`Reclaimed card ${id} (now ready)`);
|
|
4343
|
+
}
|
|
4344
|
+
return;
|
|
4345
|
+
}
|
|
4279
4346
|
if (subcommand === 'comment') {
|
|
4280
4347
|
const id = args[1];
|
|
4281
4348
|
if (!id) {
|
|
4282
4349
|
console.error('Usage: hippo card comment <id> --body "..." [--author <name>]');
|
|
4283
4350
|
process.exit(1);
|
|
4284
4351
|
}
|
|
4285
|
-
// Only show and comment look the card up directly; claim/block/review/complete throw from the store instead.
|
|
4352
|
+
// Only show and comment look the card up directly; claim/heartbeat/block/review/complete throw from the store instead.
|
|
4286
4353
|
const card = loadCard(hippoRoot, tenantId, id);
|
|
4287
4354
|
if (!card) {
|
|
4288
4355
|
console.error(`No card found with id ${id}.`);
|
|
@@ -4298,7 +4365,7 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4298
4365
|
console.log(`Added comment ${comment.id} to card ${id}`);
|
|
4299
4366
|
return;
|
|
4300
4367
|
}
|
|
4301
|
-
console.error('Usage: hippo card <create|show|list|claim|block|review|complete|comment>');
|
|
4368
|
+
console.error('Usage: hippo card <create|show|list|claim|heartbeat|block|review|complete|reclaim|comment>');
|
|
4302
4369
|
process.exit(1);
|
|
4303
4370
|
}
|
|
4304
4371
|
// ---------------------------------------------------------------------------
|
|
@@ -8224,14 +8291,20 @@ Commands:
|
|
|
8224
8291
|
--json Output as JSON
|
|
8225
8292
|
card list List cards, newest-updated first
|
|
8226
8293
|
--status <status> Filter by status
|
|
8227
|
-
card claim <id> Claim a ready or blocked card
|
|
8294
|
+
card claim <id> Claim a ready or blocked card; prints its run id and lease
|
|
8228
8295
|
--runtime <name> Claiming runtime (required)
|
|
8229
8296
|
--session <id> Session ID
|
|
8297
|
+
card heartbeat <id> Extend a running card's lease
|
|
8298
|
+
--run <n> Your run id, as card claim printed it (required)
|
|
8230
8299
|
card block <id> Block a running card
|
|
8231
8300
|
--reason "<why>" Reason recorded as a card comment (required)
|
|
8301
|
+
--run <n> Refuse unless <n> is the card's live run
|
|
8232
8302
|
card review <id> Move a running card to review
|
|
8303
|
+
--run <n> Refuse unless <n> is the card's live run
|
|
8233
8304
|
card complete <id> Complete a card in review
|
|
8234
8305
|
--outcome <o> success | failure | partial (required)
|
|
8306
|
+
--run <n> Refuse unless <n> is the card's live run
|
|
8307
|
+
card reclaim Return every running card whose lease has expired to ready
|
|
8235
8308
|
card comment <id> Add a comment to a card
|
|
8236
8309
|
--body <text> Comment body (required)
|
|
8237
8310
|
--author <name> Comment author (default: cli)
|
|
@@ -8463,6 +8536,8 @@ Examples:
|
|
|
8463
8536
|
hippo card create --title "Add cards table" --repo hippo --depends-on card_abc
|
|
8464
8537
|
hippo card claim card_abc --runtime codex
|
|
8465
8538
|
hippo card complete card_abc --outcome success
|
|
8539
|
+
hippo card heartbeat card_abc --run 7
|
|
8540
|
+
hippo card reclaim
|
|
8466
8541
|
hippo embed --status
|
|
8467
8542
|
hippo watch "npm run build"
|
|
8468
8543
|
hippo learn --git --days 30
|