@c4a/context-cli 0.6.0-beta.3 → 0.6.0-beta.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/cli.js
CHANGED
|
@@ -49728,8 +49728,15 @@ function extractPhaseSourceFingerprint(input) {
|
|
|
49728
49728
|
ref: source3.record.git.ref,
|
|
49729
49729
|
...source3.status.head !== undefined ? { head: source3.status.head } : {},
|
|
49730
49730
|
...source3.record.subpath !== undefined ? { subpath: source3.record.subpath } : {},
|
|
49731
|
+
scopeHash: source3.status.scopeHash ?? "unknown",
|
|
49731
49732
|
materializedAt: source3.status.materializedAt
|
|
49732
49733
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
49734
|
+
const freshnessSources = sources.map((source3) => ({
|
|
49735
|
+
name: source3.name,
|
|
49736
|
+
...source3.subpath !== undefined ? { subpath: source3.subpath } : {},
|
|
49737
|
+
scopeHash: source3.scopeHash,
|
|
49738
|
+
materializedAt: source3.materializedAt
|
|
49739
|
+
}));
|
|
49733
49740
|
const fingerprint = stableHash({
|
|
49734
49741
|
phase: {
|
|
49735
49742
|
id: input.phase.id,
|
|
@@ -49743,7 +49750,7 @@ function extractPhaseSourceFingerprint(input) {
|
|
|
49743
49750
|
exportedOnly: input.phase.exportedOnly,
|
|
49744
49751
|
transform: transformFingerprint(input.phase)
|
|
49745
49752
|
},
|
|
49746
|
-
sources
|
|
49753
|
+
sources: freshnessSources
|
|
49747
49754
|
});
|
|
49748
49755
|
return {
|
|
49749
49756
|
phaseId: input.phase.id,
|
|
@@ -50510,12 +50517,19 @@ async function normalizeInputRef(input) {
|
|
|
50510
50517
|
}
|
|
50511
50518
|
return resolved.toLowerCase();
|
|
50512
50519
|
}
|
|
50513
|
-
function
|
|
50520
|
+
async function gitTreeHash(input) {
|
|
50521
|
+
if (input.ref === undefined || !isFullCommitSha(input.ref))
|
|
50522
|
+
return;
|
|
50523
|
+
const treeish = input.subpath === undefined ? `${input.ref}^{tree}` : `${input.ref}:${input.subpath}`;
|
|
50524
|
+
const hash2 = await gitOutput(input.gitRoot, ["rev-parse", "--verify", treeish]);
|
|
50525
|
+
return hash2 !== null && /^[0-9a-f]{40}$/iu.test(hash2) ? hash2.toLowerCase() : undefined;
|
|
50526
|
+
}
|
|
50527
|
+
function validPinnedRef(ref2, diagnostics) {
|
|
50514
50528
|
if (!isFullCommitSha(ref2)) {
|
|
50515
50529
|
diagnostics.push(`registry ref must be a full 40-character commit sha: ${ref2}`);
|
|
50516
50530
|
return false;
|
|
50517
50531
|
}
|
|
50518
|
-
return
|
|
50532
|
+
return true;
|
|
50519
50533
|
}
|
|
50520
50534
|
async function normalizeAddInput(input, existing) {
|
|
50521
50535
|
const originalLocal = input.local ?? existing?.local;
|
|
@@ -50569,6 +50583,49 @@ async function normalizeAddInput(input, existing) {
|
|
|
50569
50583
|
}
|
|
50570
50584
|
};
|
|
50571
50585
|
}
|
|
50586
|
+
async function inspectRepoCheckout(input) {
|
|
50587
|
+
if (input.localAbs === null) {
|
|
50588
|
+
input.diagnostics.push("local path is not declared");
|
|
50589
|
+
input.agentHints.push("Ask the user for a local checkout path before running extraction.");
|
|
50590
|
+
return { gitRepo: false };
|
|
50591
|
+
}
|
|
50592
|
+
if (!input.localExists) {
|
|
50593
|
+
input.diagnostics.push(`local path is missing: ${input.source.local}`);
|
|
50594
|
+
input.agentHints.push(`Ask the user before cloning ${input.source.git.remote} at ${input.source.git.ref}; the CLI will not clone automatically.`);
|
|
50595
|
+
return { gitRepo: false };
|
|
50596
|
+
}
|
|
50597
|
+
const gitRoot = await resolveGitRoot(input.localAbs);
|
|
50598
|
+
if (gitRoot === null) {
|
|
50599
|
+
input.diagnostics.push(`local path is not a git repository: ${input.source.local}`);
|
|
50600
|
+
return { gitRepo: false };
|
|
50601
|
+
}
|
|
50602
|
+
if (!input.scopeExists || input.scopedAbs === null) {
|
|
50603
|
+
input.diagnostics.push(`source subpath is missing: ${input.subpath ?? "."}`);
|
|
50604
|
+
return { gitRepo: true };
|
|
50605
|
+
}
|
|
50606
|
+
const head = await readGitHead(gitRoot) ?? await gitOutput(gitRoot, ["rev-parse", "HEAD"]) ?? undefined;
|
|
50607
|
+
if (!validPinnedRef(input.source.git.ref, input.diagnostics)) {
|
|
50608
|
+
return { gitRepo: true, ...head !== undefined ? { head } : {}, scopedAbs: input.scopedAbs };
|
|
50609
|
+
}
|
|
50610
|
+
const [pinnedScopeHash, scopeHash] = await Promise.all([
|
|
50611
|
+
gitTreeHash({ gitRoot, ref: input.source.git.ref, subpath: input.subpath }),
|
|
50612
|
+
gitTreeHash({ gitRoot, ref: head, subpath: input.subpath })
|
|
50613
|
+
]);
|
|
50614
|
+
if (pinnedScopeHash === undefined) {
|
|
50615
|
+
input.diagnostics.push(`source boundary ${input.subpath ?? "."} is missing at pinned ref ${input.source.git.ref}`);
|
|
50616
|
+
input.agentHints.push("Ask the user to confirm a valid pinned source commit before updating the ref; the CLI will not change the source repository.");
|
|
50617
|
+
}
|
|
50618
|
+
if (scopeHash === undefined) {
|
|
50619
|
+
input.diagnostics.push(`source boundary ${input.subpath ?? "."} is missing at HEAD ${head ?? "<unknown>"}`);
|
|
50620
|
+
}
|
|
50621
|
+
return {
|
|
50622
|
+
gitRepo: true,
|
|
50623
|
+
...head !== undefined ? { head } : {},
|
|
50624
|
+
...pinnedScopeHash !== undefined ? { pinnedScopeHash } : {},
|
|
50625
|
+
...scopeHash !== undefined ? { scopeHash } : {},
|
|
50626
|
+
scopedAbs: input.scopedAbs
|
|
50627
|
+
};
|
|
50628
|
+
}
|
|
50572
50629
|
async function inspectRepoSource(input) {
|
|
50573
50630
|
const source3 = input.source;
|
|
50574
50631
|
const materializedAt = source3.materializedAt ?? defaultMaterializedAt(source3.name);
|
|
@@ -50579,43 +50636,36 @@ async function inspectRepoSource(input) {
|
|
|
50579
50636
|
const subpath = normalizeSubpath(source3.subpath);
|
|
50580
50637
|
const scopedAbs = localAbs === null ? null : scopedLocalPath(localAbs, subpath);
|
|
50581
50638
|
const scopeExists = scopedAbs !== null && existsSync9(scopedAbs);
|
|
50582
|
-
let gitRepo = false;
|
|
50583
|
-
let head;
|
|
50584
50639
|
let materialized = existsSync9(join13(input.projectRoot, materializedAt));
|
|
50585
|
-
|
|
50586
|
-
|
|
50587
|
-
|
|
50588
|
-
|
|
50589
|
-
|
|
50590
|
-
|
|
50591
|
-
|
|
50592
|
-
|
|
50593
|
-
|
|
50594
|
-
|
|
50595
|
-
|
|
50596
|
-
|
|
50597
|
-
|
|
50598
|
-
|
|
50599
|
-
|
|
50600
|
-
|
|
50601
|
-
|
|
50602
|
-
|
|
50603
|
-
|
|
50604
|
-
|
|
50605
|
-
|
|
50606
|
-
|
|
50607
|
-
|
|
50608
|
-
|
|
50609
|
-
diagnostics,
|
|
50610
|
-
agent_hints,
|
|
50611
|
-
sourceName: source3.name
|
|
50612
|
-
});
|
|
50613
|
-
}
|
|
50640
|
+
const checkout = await inspectRepoCheckout({
|
|
50641
|
+
source: source3,
|
|
50642
|
+
localAbs,
|
|
50643
|
+
localExists,
|
|
50644
|
+
subpath,
|
|
50645
|
+
scopeExists,
|
|
50646
|
+
scopedAbs,
|
|
50647
|
+
diagnostics,
|
|
50648
|
+
agentHints: agent_hints
|
|
50649
|
+
});
|
|
50650
|
+
if (checkout.scopedAbs !== undefined) {
|
|
50651
|
+
materialized = input.materialize ? await ensureMaterializedSymlink({
|
|
50652
|
+
projectRoot: input.projectRoot,
|
|
50653
|
+
materializedAt,
|
|
50654
|
+
localAbs: checkout.scopedAbs,
|
|
50655
|
+
diagnostics
|
|
50656
|
+
}) : await diagnoseMaterializedSymlink({
|
|
50657
|
+
projectRoot: input.projectRoot,
|
|
50658
|
+
materializedAt,
|
|
50659
|
+
localAbs: checkout.scopedAbs,
|
|
50660
|
+
diagnostics,
|
|
50661
|
+
agent_hints,
|
|
50662
|
+
sourceName: source3.name
|
|
50663
|
+
});
|
|
50614
50664
|
}
|
|
50615
|
-
const
|
|
50616
|
-
if (gitRepo && !
|
|
50617
|
-
diagnostics.push(`HEAD ${head ?? "<unknown>"} does not match pinned ref ${source3.git.ref}`);
|
|
50618
|
-
agent_hints.push("Ask the user before
|
|
50665
|
+
const scopeMatches = checkout.pinnedScopeHash !== undefined && checkout.scopeHash !== undefined && checkout.pinnedScopeHash === checkout.scopeHash;
|
|
50666
|
+
if (checkout.gitRepo && checkout.pinnedScopeHash !== undefined && checkout.scopeHash !== undefined && !scopeMatches) {
|
|
50667
|
+
diagnostics.push(`source boundary ${subpath ?? "."} hash ${checkout.scopeHash} at HEAD ${checkout.head ?? "<unknown>"} does not match pinned ref ${source3.git.ref} hash ${checkout.pinnedScopeHash}`);
|
|
50668
|
+
agent_hints.push("Ask the user to confirm the changed source boundary before updating its pinned ref; the CLI will not change the source repository.");
|
|
50619
50669
|
}
|
|
50620
50670
|
return {
|
|
50621
50671
|
name: source3.name,
|
|
@@ -50627,10 +50677,12 @@ async function inspectRepoSource(input) {
|
|
|
50627
50677
|
materialized,
|
|
50628
50678
|
localExists,
|
|
50629
50679
|
...subpath !== undefined ? { scopeExists } : {},
|
|
50630
|
-
gitRepo,
|
|
50631
|
-
...head !== undefined ? { head } : {},
|
|
50632
|
-
|
|
50633
|
-
|
|
50680
|
+
gitRepo: checkout.gitRepo,
|
|
50681
|
+
...checkout.head !== undefined ? { head: checkout.head } : {},
|
|
50682
|
+
...checkout.pinnedScopeHash !== undefined ? { pinnedScopeHash: checkout.pinnedScopeHash } : {},
|
|
50683
|
+
...checkout.scopeHash !== undefined ? { scopeHash: checkout.scopeHash } : {},
|
|
50684
|
+
scopeMatches,
|
|
50685
|
+
ready: localExists && scopeExists && checkout.gitRepo && scopeMatches && materialized && diagnostics.length === 0,
|
|
50634
50686
|
diagnostics,
|
|
50635
50687
|
agent_hints
|
|
50636
50688
|
};
|
|
@@ -51216,6 +51268,7 @@ async function previewExtractTsPhase(input) {
|
|
|
51216
51268
|
name: source3.record.name,
|
|
51217
51269
|
ref: source3.record.git.ref,
|
|
51218
51270
|
...source3.status.head !== undefined ? { head: source3.status.head } : {},
|
|
51271
|
+
scopeHash: source3.status.scopeHash ?? "unknown",
|
|
51219
51272
|
materializedAt: source3.status.materializedAt,
|
|
51220
51273
|
modules,
|
|
51221
51274
|
moduleErrors
|
|
@@ -56886,6 +56939,7 @@ function selectedSourcesForExtractPhase(input) {
|
|
|
56886
56939
|
record: source3,
|
|
56887
56940
|
status: {
|
|
56888
56941
|
...sourceStatus?.head !== undefined ? { head: sourceStatus.head } : {},
|
|
56942
|
+
...sourceStatus?.scopeHash !== undefined ? { scopeHash: sourceStatus.scopeHash } : {},
|
|
56889
56943
|
materializedAt: sourceStatus?.materializedAt ?? defaultMaterializedAt2(source3)
|
|
56890
56944
|
}
|
|
56891
56945
|
};
|
|
@@ -68758,6 +68812,9 @@ async function loadConfirmedStructure(input) {
|
|
|
68758
68812
|
approvedStructureRestore: true
|
|
68759
68813
|
});
|
|
68760
68814
|
if (validated2.payload === undefined || !validated2.result.valid) {
|
|
68815
|
+
if ((input.allowInvalidStructureForReadOnly === true || input.allowInvalidApprovedStructureForReadOnly === true) && validated2.payload !== undefined) {
|
|
68816
|
+
return validated2.payload;
|
|
68817
|
+
}
|
|
68761
68818
|
throw workspaceError2("knowledge/structure.yaml is not valid for compile", {
|
|
68762
68819
|
path: APPROVED_STRUCTURE_FILE,
|
|
68763
68820
|
diagnostics: validated2.result.diagnostics,
|
|
@@ -68847,7 +68904,8 @@ async function loadCompileInput(input) {
|
|
|
68847
68904
|
projectRoot: input.projectRoot,
|
|
68848
68905
|
phase: input.phase,
|
|
68849
68906
|
evidence,
|
|
68850
|
-
...input.allowInvalidStructureForReadOnly === true ? { allowInvalidStructureForReadOnly: true } : {}
|
|
68907
|
+
...input.allowInvalidStructureForReadOnly === true ? { allowInvalidStructureForReadOnly: true } : {},
|
|
68908
|
+
...input.allowInvalidApprovedStructureForReadOnly === true ? { allowInvalidApprovedStructureForReadOnly: true } : {}
|
|
68851
68909
|
});
|
|
68852
68910
|
if (input.allowInvalidStructureForReadOnly === true) {
|
|
68853
68911
|
return { evidence, structure };
|
|
@@ -69519,7 +69577,7 @@ async function runCompileProsePhase(input) {
|
|
|
69519
69577
|
const view = input.options.schema === true ? "schema" : input.options.view ?? (input.options.validate || input.options.stage ? undefined : "read-plan");
|
|
69520
69578
|
const { evidence, structure } = await loadCompileInput({
|
|
69521
69579
|
...input,
|
|
69522
|
-
...(view === "blockers" || view === "schema") && input.options.validate !== true && input.options.stage !== true ? { allowInvalidStructureForReadOnly: true } : {}
|
|
69580
|
+
...(view === "blockers" || view === "schema") && input.options.validate !== true && input.options.stage !== true ? { allowInvalidStructureForReadOnly: true } : view !== undefined && input.options.validate !== true && input.options.stage !== true ? { allowInvalidApprovedStructureForReadOnly: true } : {}
|
|
69523
69581
|
});
|
|
69524
69582
|
if (input.options.validate !== true && input.options.stage !== true) {
|
|
69525
69583
|
return await runCompileViewRequest({
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c4a/context-cli",
|
|
3
|
-
"version": "0.6.0-beta.
|
|
3
|
+
"version": "0.6.0-beta.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"context": "./cli.js"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@c4a/context": "0.6.0-beta.
|
|
9
|
+
"@c4a/context": "0.6.0-beta.4",
|
|
10
10
|
"commander": "^11.0.0",
|
|
11
11
|
"handlebars": "^4.7.8",
|
|
12
12
|
"ink": "^5.0.0",
|
package/plugins/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.6.0-beta.
|
|
1
|
+
0.6.0-beta.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context",
|
|
3
|
-
"version": "0.6.0-beta.
|
|
3
|
+
"version": "0.6.0-beta.4",
|
|
4
4
|
"description": "Maintain a project-local knowledge workspace through init and next-step agent guidance.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "c4a"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"skills": "./skills/",
|
|
19
19
|
"interface": {
|
|
20
20
|
"displayName": "C4A Context",
|
|
21
|
-
"shortDescription": "Initialize and advance a local, source-linked project knowledge workspace.\nv0.6.0-beta.
|
|
21
|
+
"shortDescription": "Initialize and advance a local, source-linked project knowledge workspace.\nv0.6.0-beta.4",
|
|
22
22
|
"longDescription": "Create a Context workspace and use agent-guided next steps to register sources, run extraction, review candidates, build package outputs, and verify health without silently mutating source repositories.",
|
|
23
23
|
"developerName": "c4a",
|
|
24
24
|
"category": "Productivity",
|