summaryrefslogtreecommitdiff
path: root/src/cli/export.c
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-04 17:21:32 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-04 17:21:32 +0900
commit0634f2048c7c9a474aab1d8104b964b3bf70a064 (patch)
tree508c305a64cbd3b01f5146776e22865d283d5dbb /src/cli/export.c
parenteb5e9d9f37bda7d78f69614da70402357794168a (diff)
feat(P1-002): migrate offline JSONL import/export to dedicated CLI
- Replace the MCP import_messages tool with standalone CLI commands: iny-convmem-mcp --data-dir <path> --import <file> iny-convmem-mcp --data-dir <path> --export <file> - Add src/cli/{import,export,cli.h} and a CTest process test (tiny-convmem-mcp.cli) covering round-trip, manifest generation, overwrite/reject policies, and include_deleted export. - Fix Debug heap corruption in iny_store_import() by deep-copying imported messages instead of taking ownership of caller-allocated records, which were later freed by the caller. - Remove the now-redundant src/mcp/tools/import_messages.c and keep the tool registry at 7 MCP tools. - Update docs/development-plan.md (P1-002 complete) and docs/implementation-status.md with CLI test coverage.
Diffstat (limited to 'src/cli/export.c')
-rw-r--r--src/cli/export.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/cli/export.c b/src/cli/export.c
new file mode 100644
index 0000000..4288ba4
--- /dev/null
+++ b/src/cli/export.c
@@ -0,0 +1,98 @@
+#include "cli/cli.h"
+
+#include "mcp/tools/common/common.h"
+#include "storage/codec.h"
+#include "storage/store.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+tiny_cli_export(tiny_store_t *store, const tiny_cli_options_t *options)
+{
+ size_t index;
+ size_t emitted = 0;
+ FILE *output = NULL;
+ tiny_json_buffer_t item;
+
+ if (!options || !options->export_path)
+ {
+ fprintf(stderr, "export: path is required\n");
+ return 1;
+ }
+
+ if (strcmp(options->export_path, "-") == 0)
+ {
+ output = stdout;
+ }
+ else
+ {
+ if (fopen_s(&output, options->export_path, "wb") != 0 || !output)
+ {
+ fprintf(stderr, "export: unable to open '%s'\n", options->export_path);
+ return 1;
+ }
+ }
+
+ if (fprintf(output, "{\"type\":\"tiny-convmem-manifest\",\"format_version\":2}\n") < 0)
+ {
+ fprintf(stderr, "export: failed to write manifest\n");
+ if (output != stdout)
+ {
+ fclose(output);
+ }
+ return 1;
+ }
+
+ for (index = 0; index < tiny_store_entry_count(store); ++index)
+ {
+ const tiny_store_entry_t *entry = tiny_store_entry(store, index);
+ int write_failed;
+ if (!entry)
+ {
+ continue;
+ }
+ if (entry->deleted && !options->include_deleted)
+ {
+ continue;
+ }
+ if (options->session_id && options->session_id[0]
+ && strcmp(entry->message.session_id, options->session_id) != 0)
+ {
+ continue;
+ }
+
+ tiny_json_init(&item);
+ if (entry->deleted)
+ {
+ tiny_json_raw(&item, "{\"type\":\"DEL\",\"message_id\":");
+ tiny_json_string(&item, entry->message.message_id);
+ tiny_json_raw(&item, "}");
+ }
+ else
+ {
+ tiny_mcp_tool_append_message(&item, &entry->message);
+ }
+
+ write_failed = item.failed || fprintf(output, "%s\n", item.data ? item.data : "") < 0;
+ tiny_json_free(&item);
+ if (write_failed)
+ {
+ fprintf(stderr, "export: failed to write record\n");
+ if (output != stdout)
+ {
+ fclose(output);
+ }
+ return 1;
+ }
+ emitted++;
+ }
+
+ if (output != stdout)
+ {
+ fclose(output);
+ }
+ (void)emitted;
+ return 0;
+}